Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specific docs file type write #577

Merged
merged 8 commits into from Jan 18, 2022
20 changes: 16 additions & 4 deletions README.md
Expand Up @@ -41,6 +41,7 @@ Swag converts Go annotations to Swagger Documentation 2.0. We've created a varie
- [Rename model to display](#rename-model-to-display)
- [How to use security annotations](#how-to-use-security-annotations)
- [Add a description for enum items](#add-a-description-for-enum-items)
- [Generate only specific docs file types](#generate-only-specific-docs-file-types)
- [About the Project](#about-the-project)

## Getting started
Expand Down Expand Up @@ -86,18 +87,20 @@ USAGE:

OPTIONS:
--generalInfo value, -g value Go file path in which 'swagger general API Info' is written (default: "main.go")
--dir value, -d value Directory you want to parse (default: "./")
--dir value, -d value Directories you want to parse,comma separated and general-info file must be in the first one (default: "./")
--exclude value Exclude directories and files when searching, comma separated
--propertyStrategy value, -p value Property Naming Strategy like snakecase,camelcase,pascalcase (default: "camelcase")
--output value, -o value Output directory for all the generated files(swagger.json, swagger.yaml and doc.go) (default: "./docs")
--output value, -o value Output directory for all the generated files(swagger.json, swagger.yaml and docs.go) (default: "./docs")
--outputTypes value, --ot value Output types of generated files (docs.go, swagger.json, swagger.yaml) like go,json,yaml (default: "go,json,yaml")
--parseVendor Parse go files in 'vendor' folder, disabled by default (default: false)
--parseDependency Parse go files in outside dependency folder, disabled by default (default: false)
--parseDependency, --pd Parse go files inside dependency folder, disabled by default (default: false)
--markdownFiles value, --md value Parse folder containing markdown files to use as description, disabled by default
--codeExampleFiles value, --cef value Parse folder containing code example files to use for the x-codeSamples extension, disabled by default
--parseInternal Parse go files in internal packages, disabled by default (default: false)
--generatedTime Generate timestamp at the top of docs.go, disabled by default (default: false)
--parseDepth value Dependency parse depth (default: 100)
--instanceName value Set the swagger document instance name (default: "swagger")
--instanceName value This parameter can be used to name different swagger document instances. It is optional.
--overridesFile value File to read global type overrides from. (default: ".swaggo")
--help, -h show help (default: false)
```

Expand Down Expand Up @@ -797,6 +800,15 @@ type Example struct {
}
```

### Generate only specific docs file types

By default `swag` command generates Swagger specification in three different files/file types:
- docs.go
- swagger.json
- swagger.yaml

If you would like to limit a set of file types which should be generated you can use `--outputTypes` (short `-ot`) flag. Default value is `go,json,yaml` - output types separated with comma. To limit output only to `go` and `yaml` files, you would write `go,yaml`. With complete command that would be `swag init --outputTypes go,yaml`.

## About the Project
This project was inspired by [yvasiyarov/swagger](https://github.com/yvasiyarov/swagger) but we simplified the usage and added support a variety of [web frameworks](#supported-web-frameworks). Gopher image source is [tenntenn/gopher-stickers](https://github.com/tenntenn/gopher-stickers). It has licenses [creative commons licensing](http://creativecommons.org/licenses/by/3.0/deed.en).
## Contributors
Expand Down
16 changes: 15 additions & 1 deletion cmd/swag/main.go
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"log"
"os"
"strings"

"github.com/urfave/cli/v2"

Expand All @@ -18,6 +19,7 @@ const (
generalInfoFlag = "generalInfo"
propertyStrategyFlag = "propertyStrategy"
outputFlag = "output"
outputTypesFlag = "outputTypes"
parseVendorFlag = "parseVendor"
parseDependencyFlag = "parseDependency"
markdownFilesFlag = "markdownFiles"
Expand Down Expand Up @@ -56,7 +58,13 @@ var initFlags = []cli.Flag{
Name: outputFlag,
Aliases: []string{"o"},
Value: "./docs",
Usage: "Output directory for all the generated files(swagger.json, swagger.yaml and doc.go)",
Usage: "Output directory for all the generated files(swagger.json, swagger.yaml and docs.go)",
},
&cli.StringFlag{
Name: outputTypesFlag,
Aliases: []string{"ot"},
Value: "go,json,yaml",
Usage: "Output types of generated files (docs.go, swagger.json, swagger.yaml) like go,json,yaml",
},
&cli.BoolFlag{
Name: parseVendorFlag,
Expand Down Expand Up @@ -113,12 +121,18 @@ func initAction(c *cli.Context) error {
return fmt.Errorf("not supported %s propertyStrategy", strategy)
}

outputTypes := strings.Split(c.String(outputTypesFlag), ",")
if len(outputTypes) == 0 {
return fmt.Errorf("no output types specified")
}

return gen.New().Build(&gen.Config{
SearchDir: c.String(searchDirFlag),
Excludes: c.String(excludeFlag),
MainAPIFile: c.String(generalInfoFlag),
PropNamingStrategy: strategy,
OutputDir: c.String(outputFlag),
OutputTypes: outputTypes,
ParseVendor: c.Bool(parseVendorFlag),
ParseDependency: c.Bool(parseDependencyFlag),
MarkdownFilesDir: c.String(markdownFilesFlag),
Expand Down
88 changes: 69 additions & 19 deletions gen/gen.go
Expand Up @@ -9,6 +9,7 @@ import (
"io"
"log"
"os"
"path"
"path/filepath"
"strings"
"text/template"
Expand All @@ -24,20 +25,36 @@ var open = os.Open
// DefaultOverridesFile is the location swaggo will look for type overrides.
const DefaultOverridesFile = ".swaggo"

type genTypeWriter func(*Config, *spec.Swagger) error

// Gen presents a generate tool for swag.
type Gen struct {
jsonIndent func(data interface{}) ([]byte, error)
jsonToYAML func(data []byte) ([]byte, error)
json func(data interface{}) ([]byte, error)
jsonIndent func(data interface{}) ([]byte, error)
jsonToYAML func(data []byte) ([]byte, error)
outputTypeMap map[string]genTypeWriter
}

// New creates a new Gen.
func New() *Gen {
return &Gen{
gen := &Gen{
json: func(data interface{}) ([]byte, error) {
return json.Marshal(data)
},
jsonIndent: func(data interface{}) ([]byte, error) {
return json.MarshalIndent(data, "", " ")
},
jsonToYAML: yaml.JSONToYAML,
}

gen.outputTypeMap = map[string]genTypeWriter{
"go": gen.writeDocSwagger,
"json": gen.writeJSONSwagger,
"yaml": gen.writeYAMLSwagger,
"yml": gen.writeYAMLSwagger,
}

return gen
}

// Config presents Gen configurations.
Expand All @@ -51,6 +68,9 @@ type Config struct {
// OutputDir represents the output directory for all the generated files
OutputDir string

// OutputTypes define types of files which should be generated
OutputTypes []string

// MainAPIFile the Go file path in which 'swagger general API Info' is written
MainAPIFile string

Expand Down Expand Up @@ -137,55 +157,85 @@ func (g *Gen) Build(config *Config) error {
}
swagger := p.GetSwagger()

b, err := g.jsonIndent(swagger)
if err != nil {
if err := os.MkdirAll(config.OutputDir, os.ModePerm); err != nil {
return err
}

if err := os.MkdirAll(config.OutputDir, os.ModePerm); err != nil {
return err
for _, outputType := range config.OutputTypes {
outputType = strings.ToLower(strings.TrimSpace(outputType))
if typeWriter, ok := g.outputTypeMap[outputType]; ok {
if err := typeWriter(config, swagger); err != nil {
return err
}
} else {
log.Printf("output type '%s' not supported", outputType)
}
}

return nil
}

func (g *Gen) writeDocSwagger(config *Config, swagger *spec.Swagger) error {
docFileName := path.Join(config.OutputDir, "docs.go")

absOutputDir, err := filepath.Abs(config.OutputDir)
if err != nil {
return err
}
packageName := filepath.Base(absOutputDir)
docFileName := filepath.Join(config.OutputDir, "docs.go")
jsonFileName := filepath.Join(config.OutputDir, "swagger.json")
yamlFileName := filepath.Join(config.OutputDir, "swagger.yaml")

docs, err := os.Create(docFileName)
if err != nil {
return err
}
defer docs.Close()

err = g.writeFile(b, jsonFileName)
// Write doc
err = g.writeGoDoc(packageName, docs, swagger, config)
if err != nil {
return err
}

y, err := g.jsonToYAML(b)
log.Printf("create docs.go at %+v", docFileName)
return nil
}

func (g *Gen) writeJSONSwagger(config *Config, swagger *spec.Swagger) error {
jsonFileName := path.Join(config.OutputDir, "swagger.json")

b, err := g.jsonIndent(swagger)
if err != nil {
return fmt.Errorf("cannot convert json to yaml error: %s", err)
return err
}

err = g.writeFile(y, yamlFileName)
err = g.writeFile(b, jsonFileName)
if err != nil {
return err
}

// Write doc
err = g.writeGoDoc(packageName, docs, swagger, config)
log.Printf("create swagger.json at %+v", jsonFileName)
return nil
}

func (g *Gen) writeYAMLSwagger(config *Config, swagger *spec.Swagger) error {
yamlFileName := path.Join(config.OutputDir, "swagger.yaml")

b, err := g.json(swagger)
if err != nil {
return err
}

log.Printf("create docs.go at %+v", docFileName)
log.Printf("create swagger.json at %+v", jsonFileName)
log.Printf("create swagger.yaml at %+v", yamlFileName)
y, err := g.jsonToYAML(b)
if err != nil {
return fmt.Errorf("cannot covert json to yaml error: %s", err)
}

err = g.writeFile(y, yamlFileName)
if err != nil {
return err
}

log.Printf("create swagger.yaml at %+v", yamlFileName)
return nil
}

Expand Down