# 🔄 Migration Guide: From go-zero Plugin to Standalone Tool

This document explains how `go-doc` was extracted from go-zero and made independent.

## 📊 What Changed?

### 1. **Module Independence**

**Before (go-zero plugin):**
```go
// Part of go-zero's internal tools
package swagger // in tools/goctl/api/plugin/swagger/
```

**After (standalone):**
```go
module go-doc

package swagger // in internal/swagger/
```

### 2. **Dependency Reduction**

#### Removed Internal Dependencies

| Dependency | Replaced With | Reason |
|:-----------|:--------------|:-------|
| `go-zero/tools/goctl/internal/version` | Custom version in `main.go` | Internal package not accessible |
| `go-zero/tools/goctl/util` | `go-doc/internal/util` | Self-contained utilities |
| `go-zero/tools/goctl/util/stringx` | `go-doc/internal/util` | Custom string manipulation |
| `go-zero/tools/goctl/util/pathx` | `go-doc/internal/util` | Custom path utilities |
| `google.golang.org/grpc/metadata` | Direct map access | Simplified KV retrieval |

#### Kept Essential Dependencies

```go
require (
    github.com/go-openapi/spec v0.21.0           // Swagger spec
    github.com/spf13/cobra v1.8.1                // CLI framework
    github.com/zeromicro/go-zero/tools/goctl v1.9.0  // API parser only
    gopkg.in/yaml.v2 v2.4.0                      // YAML output
)
```

### 3. **Project Structure**

**Before:**
```
go-zero/
└── tools/
    └── goctl/
        └── api/
            └── plugin/
                └── swagger/
                    ├── swagger.go
                    ├── parameter.go
                    └── ...
```

**After:**
```
go-doc/
├── cmd/
│   └── go-doc/
│       └── main.go          # Standalone entry point
├── internal/
│   ├── swagger/             # Core logic (from go-zero)
│   │   ├── swagger.go
│   │   ├── parameter.go
│   │   └── ...
│   └── util/                # Self-contained utilities
│       ├── util.go
│       ├── stringx.go
│       └── pathx.go
└── example/
```

### 4. **Import Path Changes**

**Before:**
```go
import (
    "github.com/zeromicro/go-zero/tools/goctl/util"
    "github.com/zeromicro/go-zero/tools/goctl/util/stringx"
    "github.com/zeromicro/go-zero/tools/goctl/internal/version"
    "google.golang.org/grpc/metadata"
)
```

**After:**
```go
import (
    "go-doc/internal/util"
)
```

### 5. **Metadata Handling**

**Before (using gRPC metadata):**
```go
func getStringFromKV(properties map[string]string, key string) string {
    md := metadata.New(properties)
    val := md.Get(key)
    if len(val) == 0 {
        return ""
    }
    return val[0]
}
```

**After (direct map access):**
```go
func getStringFromKVOrDefault(properties map[string]string, key string, def string) string {
    if len(properties) == 0 {
        return def
    }
    val, ok := properties[key]
    if !ok {
        return def
    }
    str, err := strconv.Unquote(val)
    if err != nil || len(str) == 0 {
        return def
    }
    return str
}
```

### 6. **Version Information**

**Before:**
```go
ext.Add("x-goctl-version", version.BuildVersion)
ext.Add("x-github", "https://github.com/zeromicro/go-zero")
```

**After:**
```go
ext.Add("x-generator", "go-doc")
ext.Add("x-github", "https://github.com/danielchan-25/go-doc")
```

## 🔧 Implementation Details

### Custom Utilities Created

#### 1. **util.TrimWhiteSpace**
```go
// Replaces: go-zero/tools/goctl/util.TrimWhiteSpace
func TrimWhiteSpace(s string) string {
    return strings.Map(func(r rune) rune {
        if unicode.IsSpace(r) {
            return -1
        }
        return r
    }, s)
}
```

#### 2. **util.FieldsAndTrimSpace**
```go
// Replaces: go-zero/tools/goctl/util.FieldsAndTrimSpace
func FieldsAndTrimSpace(s string, fn func(rune) bool) []string {
    fields := strings.FieldsFunc(s, fn)
    result := make([]string, 0, len(fields))
    for _, field := range fields {
        trimmed := strings.TrimSpace(field)
        if len(trimmed) > 0 {
            result = append(result, trimmed)
        }
    }
    return result
}
```

#### 3. **util.String (for ToCamel/Untitle)**
```go
// Replaces: go-zero/tools/goctl/util/stringx
type String struct {
    source string
}

func From(s string) String {
    return String{source: s}
}

func (s String) ToCamel() string { /* implementation */ }
func (s String) Untitle() string { /* implementation */ }
```

#### 4. **util.MkdirIfNotExist**
```go
// Replaces: go-zero/tools/goctl/util/pathx.MkdirIfNotExist
func MkdirIfNotExist(dir string) error {
    if _, err := os.Stat(dir); os.IsNotExist(err) {
        return os.MkdirAll(dir, 0755)
    }
    return nil
}
```

## ✅ Compatibility

### What's Still Compatible?

✅ **API File Format** - 100% compatible with go-zero `.api` files  
✅ **Swagger Output** - Generates identical OpenAPI 2.0 specifications  
✅ **All Features** - All swagger generation features preserved  
✅ **Tag Syntax** - Same tag options (range, enum, default, example, etc.)

### What's Different?

⚠️ **Generated Metadata**
- `x-generator: "go-doc"` instead of `x-goctl-version`
- `x-github` points to go-doc repository
- Build date format remains the same

⚠️ **Module Name**
- Import as `go-doc` not part of go-zero

⚠️ **Binary Name**
- `go-doc` instead of `goctl api plugin -plugin swagger`

## 🚀 Migration Steps for Users

If you were using go-zero's swagger plugin:

### Old Way (go-zero plugin):
```bash
goctl api plugin -plugin swagger -api example.api -dir output
```

### New Way (standalone go-doc):
```bash
go-doc -a example.api -d output
```

## 📝 Benefits of Independence

1. ✅ **Smaller Binary** - Only swagger generation, no full goctl
2. ✅ **Faster Installation** - Fewer dependencies
3. ✅ **Clearer Purpose** - Single responsibility
4. ✅ **Easier Maintenance** - Self-contained codebase
5. ✅ **Flexible Updates** - Independent release cycle

## 🙏 Attribution

This tool was extracted from the excellent [go-zero](https://github.com/zeromicro/go-zero) 
project. We are grateful to the go-zero team for their foundational work.

---

**Original Source:** https://github.com/zeromicro/go-zero/tree/master/tools/goctl/api/plugin/swagger  
**License:** MIT (both original and this project)

