Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ bin/
# Air tmp files
tmp

.idea
259 changes: 259 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Taskw is a Go CLI tool that generates code for Go APIs using the Fiber web framework, Wire dependency injection, and Swaggo annotations. It eliminates boilerplate by scanning your code for annotations and provider functions to automatically generate route registration and dependency injection code.

**Core Technologies:**
- Go 1.24.1
- Fiber v2 (web framework)
- Google Wire (dependency injection)
- Swaggo (OpenAPI/Swagger annotations)
- Cobra (CLI framework)
- Viper (configuration management)

## Common Development Commands

### Build and Install
```bash
# Build the binary
task build

# Install development version to PATH
task install-dev

# Install production version to PATH
task install

# Build manually
go build -o bin/taskw main.go
```

### Testing
```bash
# Run all tests
task test

# Run end-to-end tests
task test-e2e

# Run tests manually
go test -v ./...
go test -v ./test/e2e/...
```

### Code Generation
The project uses Wire for dependency injection. After making changes to providers:
```bash
# Generate Wire code
go generate ./...

# Or specifically for CLI services
go generate ./internal/cli/
```

### Using Taskw CLI
```bash
# Initialize new project
taskw init [module-name]

# Generate all code
taskw generate
taskw generate all

# Generate specific components
taskw generate routes
taskw generate deps

# Scan and preview what will be generated
taskw scan

# Clean generated files
taskw clean
```

## Architecture Overview

### Project Structure
```
taskw/
├── cmd/taskw/ # CLI entry point (Cobra commands)
├── internal/
│ ├── cli/ # CLI service layer with Wire DI
│ ├── config/ # Configuration management (Viper)
│ ├── scanner/ # Code scanning (AST parsing + file filtering)
│ └── generator/ # Code generation (templates + formatting)
├── main.go # Application entry point
└── taskw.yaml # Configuration file
```

### Dependency Injection Architecture

The CLI uses Wire for dependency injection with the following pattern:

1. **Services**: Located in `internal/cli/*/service.go` files
2. **Wire Configuration**: `internal/cli/wire.go` defines providers
3. **Generated Code**: `internal/cli/wire_gen.go` and `dependencies_gen.go`
4. **Container Pattern**: `cli.Container` holds all injected services

**Key Services:**
- `ui.Service`: User interface and spinner management
- `project.Service`: Project scaffolding and validation
- `scan.Service`: Code scanning and analysis
- `generation.Service`: Code generation orchestration
- `clean.Service`: Generated file cleanup
- `file.Service`: File system operations

### Route Generation Architecture

The route generator handles complex routing patterns with specificity-based ordering:

**Route Processing Pipeline:**
1. **Path Conversion**: Converts OpenAPI `{param}` format to Fiber `:param` format
2. **Specificity Scoring**: Routes are scored and sorted (more specific routes first)
3. **Package Organization**: Routes are grouped by package but sorted globally
4. **Import Path Resolution**: Automatically derives handler import paths from package structure

**Key Components:**
- `RouteGenerator`: Main route generation orchestrator
- `HandlerInfo`: Represents handler dependency injection information with full package paths
- **Specificity Algorithm**: Uses segment count and parameter penalties for routing order
- **Template System**: Embedded templates with Go formatting and import management

**Route Specificity Rules:**
- Longer paths get higher scores (1000 points per segment)
- Static segments add 100 points each
- Parameters (`:param`) subtract 100 points each
- Routes with higher scores are registered first to prevent conflicts

### Scanning Architecture

The scanner uses a hybrid approach with parallel processing:
- **File Filtering**: Identifies candidate files quickly
- **AST Parsing**: Parallel processing with semaphore-controlled goroutines (max 10)
- **Error Collection**: Non-fatal errors are collected in ScanResult.Errors

**Key Scanner Types:**
- `scanner.HandlerFunction`: Represents provider functions
- `scanner.RouteMapping`: Represents route annotations with package paths
- `scanner.ProviderFunction`: Represents Wire provider functions
- `scanner.ScanResult`: Combined scan results with error tracking
- `scanner.ScanError`: Error information with file path and type
- `scanner.ScanStatistics`: Performance metrics for debugging

**Scanner Components:**
- `Scanner`: Main hybrid scanner orchestrating file filtering and AST parsing
- `ASTScanner`: Handles Go AST parsing for annotations and providers
- `FileFilter`: Optimizes file discovery before AST parsing

## Configuration Management

Taskw uses Viper for configuration with the following hierarchy:
1. Command line flags (`--config`)
2. `taskw.yaml` file
3. Default values

**Key Configuration Sections:**
- `paths.scan_dirs`: Directories to scan for code
- `paths.output_dir`: Where to generate files
- `generation.routes.enabled`: Enable route generation
- `generation.dependencies.enabled`: Enable dependency generation

## Code Style and Patterns

### Service Pattern
All CLI functionality is organized into services with this pattern:
```go
type Service interface {
// Interface defines contract
}

type serviceImpl struct {
// Dependencies injected via constructor
}

func ProvideService(deps...) Service {
return &serviceImpl{...}
}
```

### Error Handling
Use wrapped errors with context:
```go
return fmt.Errorf("failed to scan directory %s: %w", dir, err)
```

### Template Usage
Code generation uses embedded templates in `internal/generator/templates/`:
- Templates are embedded using `//go:embed`
- Use `text/template` for Go code generation
- Apply `go/format` to generated code

### Wire Integration
When adding new services:
1. Create service interface and implementation
2. Add `Provide*` function
3. Add to `internal/cli/dependencies_gen.go` (or let Taskw generate it)
4. Run `go generate ./internal/cli/`

## Testing Approach

- **Unit Tests**: Standard Go tests in `*_test.go` files
- **E2E Tests**: Located in `test/e2e/` directory
- **Integration Tests**: Test complete CLI workflows

## Important Implementation Details

### File Generation Safety
- Generated files include header comments marking them as generated
- Clean command only removes files with generation markers
- Templates handle Go imports and formatting automatically

### CLI UX Patterns
- Use spinners for long-running operations
- Provide clear error messages with actionable suggestions
- Support both interactive and non-interactive modes

### Performance Considerations
- **Parallel Scanning**: Uses semaphore-controlled goroutines (max 10) for file processing
- **File Filtering**: Pre-filters candidates before expensive AST parsing
- **Route Specificity**: Complex scoring algorithm ensures correct route registration order
- **Error Resilience**: Non-fatal scan errors don't stop processing of other files
- **Generated Code Caching**: Files are only regenerated when source changes
- **Wire Compile-Time Safety**: Dependency injection validated at compile time

### Route Generation Specifics
- **Path Parameter Conversion**: Automatically converts `{id}` to `:id` for Fiber compatibility
- **Import Path Derivation**: Uses project module config to build correct import paths
- **Handler Reference Resolution**: Converts handler refs like `userHandler.GetUsers` to `ar.userHandler.GetUsers`
- **Deterministic Ordering**: Routes and handlers are sorted for consistent generated code

## Common Tasks for Contributors

### Adding a New CLI Command
1. Add command definition to `cmd/taskw/main.go`
2. Create service interface if complex logic needed
3. Add service implementation in `internal/cli/[service]/`
4. Wire dependencies in `internal/cli/wire.go`
5. Generate Wire code with `go generate ./internal/cli/`

### Modifying Code Generation
1. Update scanner types in `internal/scanner/types.go`
2. Modify templates in `internal/generator/templates/`
3. Update generator logic in `internal/generator/`
4. Consider route specificity impact if changing route handling
5. Test with `taskw scan` and `taskw generate`

### Working with Scanner Changes
1. Understand parallel processing model - changes affect goroutine safety
2. Update `ScanResult` struct if adding new scan data types
3. Handle errors gracefully using `ScanError` collection pattern
4. Test performance impact with `GetStatistics()` for large codebases
5. Consider AST vs file filtering trade-offs for new features

### Adding Configuration Options
1. Update config structs in `internal/config/config.go`
2. Add Viper defaults in `setDefaults()`
3. Update example `taskw.yaml` in documentation
44 changes: 0 additions & 44 deletions example/.air.toml
Original file line number Diff line number Diff line change
@@ -1,44 +0,0 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ./cmd/server"
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata", "node_modules", "bin"]
exclude_file = []
exclude_regex = ["_test.go", "_gen.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
rerun = true
rerun_delay = 500
send_interrupt = false
stop_on_error = false

[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"

[log]
main_only = false
time = false

[misc]
clean_on_exit = false

[screen]
clear_on_rebuild = false
keep_scroll = true
Empty file added example/.gitignore
Empty file.
83 changes: 83 additions & 0 deletions example/.golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
run:
timeout: 5m
tests: false

linters:
fast: true
enable:
# # --- 核心 bug 检查 ---
# - govet # Go 官方 vet 工具
# - staticcheck # 静态分析,检查 bug 和废弃 API
# - errcheck # 检查未处理的错误
# - gosimple # 代码简化建议
# - ineffassign # 检测无效赋值
# - typecheck # 类型检查
# - unused # 检查未使用的代码

# # --- 代码质量 & 风格 ---
# - gocritic # 综合代码质量检查
# - revive # 现代风格检查器
# - goconst # 检查重复字符串(只对常量化需求强的项目有价值)
# - misspell # 拼写检查
# - nolintlint # 检查 nolint 指令
# - rowserrcheck # 检查数据库 rows 错误
# - unconvert # 检查不必要的类型转换

# --- 可选 (根据项目需要开启) ---
# - gocyclo # 圈复杂度检查(容易吵,建议在 code review 抓)
# - nakedret # 裸返回检查(小函数可忍,长函数才需要)
# - noctx # http 请求缺少 context(看项目规范,常报噪音)
# - unparam # 未使用参数(接口常见,很多误报)
# - whitespace # 空白字符(基本可交给 gofumpt 处理)


# linters-settings:
# revive:
# rules:
# - name: exported
# disabled: true
# - name: package-comments
# disabled: true
# - name: line-length-limit
# disabled: true
# gocritic:
# enabled-tags:
# - diagnostic
# - experimental
# - opinionated
# - performance
# - style
# disabled-checks:
# - dupImport
# - ifElseChain
# - octalLiteral
# - whyNoLint
# - wrapperFunc
# - hugeParam
# - paramTypeCombine
# - commentedOutCode
# - nestingReduce
# - singleCaseSwitch
# - emptyStringTest
# gocyclo:
# min-complexity: 15
# goconst:
# min-len: 3
# min-occurrences: 3
# nakedret:
# max-func-lines: 30

issues:
exclude-dirs:
- vendor
- ent
- mock
exclude-files:
- ".*_gen.go"
- ".*_mock.go"

output:
formats:
- format: colored-line-number
print-issued-lines: true
print-linter-name: true
Loading