Updated libraries
This commit is contained in:
3
vendor/github.com/swaggo/swag/.gitignore
generated
vendored
3
vendor/github.com/swaggo/swag/.gitignore
generated
vendored
@ -1,4 +1,5 @@
|
||||
testdata/simple/docs
|
||||
dist
|
||||
testdata/simple*/docs
|
||||
cover.out
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
|
1
vendor/github.com/swaggo/swag/.golint_exclude
generated
vendored
1
vendor/github.com/swaggo/swag/.golint_exclude
generated
vendored
@ -1 +0,0 @@
|
||||
^example
|
19
vendor/github.com/swaggo/swag/.goreleaser.yml
generated
vendored
Normal file
19
vendor/github.com/swaggo/swag/.goreleaser.yml
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
build:
|
||||
main: cmd/swag/main.go
|
||||
archive:
|
||||
replacements:
|
||||
darwin: Darwin
|
||||
linux: Linux
|
||||
windows: Windows
|
||||
386: i386
|
||||
amd64: x86_64
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
snapshot:
|
||||
name_template: "{{ .Tag }}-next"
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
8
vendor/github.com/swaggo/swag/.travis.yml
generated
vendored
8
vendor/github.com/swaggo/swag/.travis.yml
generated
vendored
@ -1,15 +1,19 @@
|
||||
language: go
|
||||
sudo: false
|
||||
|
||||
go:
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
|
||||
before_install:
|
||||
- make deps
|
||||
install:
|
||||
- make install
|
||||
|
||||
script:
|
||||
- make fmt-check
|
||||
- make lint
|
||||
- make vet
|
||||
- make build
|
||||
- make test
|
||||
|
||||
|
80
vendor/github.com/swaggo/swag/Makefile
generated
vendored
80
vendor/github.com/swaggo/swag/Makefile
generated
vendored
@ -1,36 +1,78 @@
|
||||
#! /usr/bin/make
|
||||
GOCMD=$(shell which go)
|
||||
GOLINT=$(shell which golint)
|
||||
GOIMPORT=$(shell which goimports)
|
||||
GOBUILD=$(GOCMD) build
|
||||
GOCLEAN=$(GOCMD) clean
|
||||
GOTEST=$(GOCMD) test
|
||||
GOGET=$(GOCMD) get
|
||||
GOLIST=$(GOCMD) list
|
||||
BINARY_NAME=swag
|
||||
PACKAGES=$(shell $(GOLIST) -f {{.Dir}} ./... | grep -v /example)
|
||||
GOCMD:=$(shell which go)
|
||||
GOLINT:=$(shell which golint)
|
||||
GOIMPORT:=$(shell which goimports)
|
||||
GOFMT:=$(shell which gofmt)
|
||||
GOBUILD:=$(GOCMD) build
|
||||
GOCLEAN:=$(GOCMD) clean
|
||||
GOTEST:=$(GOCMD) test
|
||||
GOGET:=$(GOCMD) get
|
||||
GOLIST:=$(GOCMD) list
|
||||
GOVET:=$(GOCMD) vet
|
||||
|
||||
BINARY_NAME:=swag
|
||||
PACKAGES:=$(shell $(GOLIST) ./...)
|
||||
GOFILES:=$(shell find . -name "*.go" -type f)
|
||||
|
||||
export GO111MODULE := on
|
||||
|
||||
all: test build
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
$(GOBUILD) -o $(BINARY_NAME) -v ./cmd/...
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(GOTEST) -v ./...
|
||||
echo "mode: count" > coverage.out
|
||||
for PKG in $(PACKAGES); do \
|
||||
$(GOCMD) test -v -covermode=count -coverprofile=profile.out $$PKG > tmp.out; \
|
||||
cat tmp.out; \
|
||||
if grep -q "^--- FAIL" tmp.out; then \
|
||||
rm tmp.out; \
|
||||
exit 1; \
|
||||
elif grep -q "build failed" tmp.out; then \
|
||||
rm tmp.out; \
|
||||
exit; \
|
||||
fi; \
|
||||
if [ -f profile.out ]; then \
|
||||
cat profile.out | grep -v "mode:" >> coverage.out; \
|
||||
rm profile.out; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(GOCLEAN)
|
||||
rm -f $(BINARY_NAME)
|
||||
|
||||
lint:
|
||||
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
|
||||
|
||||
deps:
|
||||
.PHONY: install
|
||||
install:
|
||||
$(GOGET) -v ./...
|
||||
$(GOGET) github.com/stretchr/testify/assert
|
||||
$(GOGET) golang.org/x/lint/golint
|
||||
$(GOGET) golang.org/x/tools/cmd/goimports
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
which golint || $(GOGET) -u golang.org/x/lint/golint
|
||||
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
|
||||
|
||||
.PHONY: vet
|
||||
vet:
|
||||
$(GOVET) $(PACKAGES)
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
$(GOFMT) -s -w $(GOFILES)
|
||||
|
||||
.PHONY: fmt-check
|
||||
fmt-check:
|
||||
@diff=$$($(GOFMT) -s -d $(GOFILES)); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "Please run 'make fmt' and commit the result:"; \
|
||||
echo "$${diff}"; \
|
||||
exit 1; \
|
||||
fi;
|
||||
|
||||
.PHONY: view-covered
|
||||
view-covered:
|
||||
$(GOTEST) -coverprofile=cover.out $(TARGET)
|
||||
$(GOCMD) tool cover -html=cover.out
|
||||
$(GOCMD) tool cover -html=cover.out
|
378
vendor/github.com/swaggo/swag/README.md
generated
vendored
378
vendor/github.com/swaggo/swag/README.md
generated
vendored
@ -1,71 +1,77 @@
|
||||
# swag
|
||||
|
||||
<p align="center">
|
||||
<img alt="swaggo" src="https://raw.githubusercontent.com/swaggo/swag/master/assets/swaggo.png" width="200">
|
||||
</p>
|
||||
<img align="right" width="180px" src="https://raw.githubusercontent.com/swaggo/swag/master/assets/swaggo.png">
|
||||
|
||||
<p align="center">
|
||||
Automatically generate RESTful API documentation with Swagger 2.0 for Go.
|
||||
</p>
|
||||
[](https://travis-ci.org/swaggo/swag)
|
||||
[](https://codecov.io/gh/swaggo/swag)
|
||||
[](https://goreportcard.com/report/github.com/swaggo/swag)
|
||||
[](https://codebeat.co/projects/github-com-swaggo-swag-master)
|
||||
[](https://godoc.org/github.com/swaggo/swag)
|
||||
[](#backers)
|
||||
[](#sponsors) [](https://app.fossa.io/projects/git%2Bgithub.com%2Fswaggo%2Fswag?ref=badge_shield)
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/swaggo/swag"><img alt="Travis Status" src="https://img.shields.io/travis/swaggo/swag/master.svg"></a>
|
||||
<a href="https://codecov.io/gh/swaggo/swag"><img alt="Coverage Status" src="https://img.shields.io/codecov/c/github/swaggo/swag/master.svg"></a>
|
||||
<a href="https://goreportcard.com/badge/github.com/swaggo/swag"><img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/swaggo/swag"></a>
|
||||
<a href="https://codebeat.co/projects/github-com-swaggo-swag-master"><img alt="codebeat badge" src="https://codebeat.co/badges/71e2f5e5-9e6b-405d-baf9-7cc8b5037330" /></a>
|
||||
<a href="https://godoc.org/github.com/swaggo/swag"><img alt="Go Doc" src="https://godoc.org/github.com/swaggo/swagg?status.svg"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">gopher image source is <a href="https://github.com/tenntenn/gopher-stickers">tenntenn/gopher-stickers.</a> It has licenses <a href="http://creativecommons.org/licenses/by/3.0/deed.en">creative commons licensing.</a></p>
|
||||
|
||||
## Content
|
||||
- [Getting started](#getting-started)
|
||||
- [Go web frameworks](#supported-web-frameworks)
|
||||
- [Supported Web Frameworks](#supported-web-frameworks)
|
||||
- [How to use it with Gin](#how-to-use-it-with-gin)
|
||||
- [Implementation Status](#implementation-status)
|
||||
- [swag cli](#swag-cli)
|
||||
- [General API Info](#general-api-info)
|
||||
- [Security](#security)
|
||||
- [API Operation](#api-operation)
|
||||
- [TIPS](#tips)
|
||||
- [User defined structure with an array type](#user-defined-structure-with-an-array-type)
|
||||
- [Use multiple path params](#use-multiple-path-params)
|
||||
- [Example value of struct](#example-value-of-struct)
|
||||
- [Description of struct](#description-of-struct)
|
||||
- [About the Project](#about-the-project)
|
||||
|
||||
## Summary
|
||||
|
||||
Swag converts Go annotations to Swagger Documentation 2.0. We've created a variety of plugins for popular [Go web frameworks](#supported-web-frameworks). This allows you to quickly integrate with an existing Go project (using Swagger UI).
|
||||
|
||||
## Examples
|
||||
|
||||
[swaggo + gin](https://github.com/swaggo/swag/tree/master/example)
|
||||
|
||||
## Contents
|
||||
- [Getting started](#getting-started)
|
||||
- [Supported Web Frameworks](#supported-web-frameworks)
|
||||
- [How to use it with Gin](#how-to-use-it-with-gin)
|
||||
- [Implementation Status](#implementation-status)
|
||||
- [Declarative Comments Format](#declarative-comments-format)
|
||||
- [General API Info](##general-api-info)
|
||||
- [API Operation](#api-operation)
|
||||
- [Security](#security)
|
||||
- [Examples](#examples)
|
||||
- [Descriptions over multiple lines](#descriptions-over-multiple-lines)
|
||||
- [User defined structure with an array type](#user-defined-structure-with-an-array-type)
|
||||
- [Add a headers in response](#add-a-headers-in-response)
|
||||
- [Use multiple path params](#use-multiple-path-params)
|
||||
- [Example value of struct](#example-value-of-struct)
|
||||
- [Description of struct](#description-of-struct)
|
||||
- [Override swagger type of a struct field](#Override-swagger-type-of-a-struct-field)
|
||||
- [Add extension info to struct field](#add-extension-info-to-struct-field)
|
||||
- [How to using security annotations](#how-to-using-security-annotations)
|
||||
- [About the Project](#about-the-project)
|
||||
|
||||
## Getting started
|
||||
|
||||
1. Add comments to your API source code, [See Declarative Comments Format](#general-api-info).
|
||||
1. Add comments to your API source code, See [Declarative Comments Format](#declarative-comments-format).
|
||||
|
||||
2. Download swag by using:
|
||||
```sh
|
||||
$ go get -u github.com/swaggo/swag/cmd/swag
|
||||
```
|
||||
Or download the pre-compiled binaries binray form [release page](https://github.com/swaggo/swag/releases).
|
||||
|
||||
3. Run `swag init` in the project's root folder which contains the `main.go` file. This will parse your comments and generate the required files (`docs` folder and `docs/docs.go`).
|
||||
```sh
|
||||
$ swag init
|
||||
```
|
||||
|
||||
4. In order to serve these files, you can utilize one of our supported plugins. For go's core library, check out [net/http](https://github.com/swaggo/http-swagger).
|
||||
|
||||
* Make sure to import the generated `docs/docs.go` so that your specific configuration gets `init`'ed.
|
||||
* If your General API annotation do not live in `main.go`, you can let swag know with `-g`.
|
||||
Make sure to import the generated `docs/docs.go` so that your specific configuration gets `init`'ed. If your General API annotations do not live in `main.go`, you can let swag know with `-g` flag.
|
||||
```sh
|
||||
swag init -g http/api.go
|
||||
```
|
||||
|
||||
## swag cli
|
||||
|
||||
```sh
|
||||
$ swag init -h
|
||||
NAME:
|
||||
swag init - Create docs.go
|
||||
|
||||
USAGE:
|
||||
swag init [command options] [arguments...]
|
||||
|
||||
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: "./")
|
||||
--propertyStrategy value, -p value Property Naming Strategy like snakecase,camelcase,pascalcase (default: "camelcase")
|
||||
--output value, -o value Output directory for al the generated files(swagger.json, swagger.yaml and doc.go) (default: "./docs")
|
||||
--parseVendor Parse go files in 'vendor' folder, disabled by default --output value, -o value Output directory for al the generated files(swagger.json, swagger.yaml and doc.go) (default: "./docs")
|
||||
```
|
||||
|
||||
## Supported Web Frameworks
|
||||
|
||||
- [gin](http://github.com/swaggo/gin-swagger)
|
||||
@ -215,6 +221,7 @@ import (
|
||||
// @Produce json
|
||||
// @Param id path int true "Account ID"
|
||||
// @Success 200 {object} model.Account
|
||||
// @Header 200 {string} Token "qwerty"
|
||||
// @Failure 400 {object} httputil.HTTPError
|
||||
// @Failure 404 {object} httputil.HTTPError
|
||||
// @Failure 500 {object} httputil.HTTPError
|
||||
@ -241,6 +248,7 @@ func (c *Controller) ShowAccount(ctx *gin.Context) {
|
||||
// @Produce json
|
||||
// @Param q query string false "name search by q"
|
||||
// @Success 200 {array} model.Account
|
||||
// @Header 200 {string} Token "qwerty"
|
||||
// @Failure 400 {object} httputil.HTTPError
|
||||
// @Failure 404 {object} httputil.HTTPError
|
||||
// @Failure 500 {object} httputil.HTTPError
|
||||
@ -286,67 +294,33 @@ $ swag init
|
||||
- [x] Grouping Operations With Tags
|
||||
- [ ] Swagger Extensions
|
||||
|
||||
# swag cli
|
||||
# Declarative Comments Format
|
||||
|
||||
```console
|
||||
$ swag init -h
|
||||
NAME:
|
||||
swag init - Create docs.go
|
||||
|
||||
USAGE:
|
||||
swag init [command options] [arguments...]
|
||||
|
||||
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: "./")
|
||||
--swagger value, -s value Output the swagger conf for json and yaml (default: "./docs/swagger")
|
||||
--propertyStrategy value, -p value Property Naming Strategy like snakecase,camelcase,pascalcase (default: "camelcase")
|
||||
```
|
||||
|
||||
# General API Info
|
||||
## General API Info
|
||||
|
||||
**Example**
|
||||
[celler/main.go](https://github.com/swaggo/swag/blob/master/example/celler/main.go)
|
||||
|
||||
| annotation | description | example |
|
||||
|-----------------------|-------------------------------------------------------------------------------------------------|-----------------------------------------------------------------|
|
||||
| title | **Required.** The title of the application. | // @title Swagger Example API |
|
||||
| version | **Required.** Provides the version of the application API. | // @version 1.0 |
|
||||
| description | A short description of the application. | // @description This is a sample server celler server. |
|
||||
| tag.name | Name of a tag. | // @tag.name This is the name of the tag |
|
||||
| tag.description | Description of the tag | // @tag.description Cool Description |
|
||||
| tag.docs.url | Url of the external Documentation of the tag | // @tag.docs.url https://example.com |
|
||||
| tag.docs.descripiton | Description of the external Documentation of the tag | // @tag.docs.descirption Best example documentation |
|
||||
| termsOfService | The Terms of Service for the API. | // @termsOfService http://swagger.io/terms/ |
|
||||
| contact.name | The contact information for the exposed API. | // @contact.name API Support |
|
||||
| contact.url | The URL pointing to the contact information. MUST be in the format of a URL. | // @contact.url http://www.swagger.io/support |
|
||||
| contact.email | The email address of the contact person/organization. MUST be in the format of an email address.| // @contact.email support@swagger.io |
|
||||
| license.name | **Required.** The license name used for the API. | // @license.name Apache 2.0 |
|
||||
| license.url | A URL to the license used for the API. MUST be in the format of a URL. | // @license.url http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| host | The host (name or ip) serving the API. | // @host localhost:8080 |
|
||||
| BasePath | The base path on which the API is served. | // @BasePath /api/v1 |
|
||||
| annotation | description | example |
|
||||
|-------------|--------------------------------------------|---------------------------------|
|
||||
| title | **Required.** The title of the application.| // @title Swagger Example API |
|
||||
| version | **Required.** Provides the version of the application API.| // @version 1.0 |
|
||||
| description | A short description of the application. |// @description This is a sample server celler server. |
|
||||
| tag.name | Name of a tag.| // @tag.name This is the name of the tag |
|
||||
| tag.description | Description of the tag | // @tag.description Cool Description |
|
||||
| tag.docs.url | Url of the external Documentation of the tag | // @tag.docs.url https://example.com|
|
||||
| tag.docs.descripiton | Description of the external Documentation of the tag| // @tag.docs.descirption Best example documentation |
|
||||
| termsOfService | The Terms of Service for the API.| // @termsOfService http://swagger.io/terms/ |
|
||||
| contact.name | The contact information for the exposed API.| // @contact.name API Support |
|
||||
| contact.url | The URL pointing to the contact information. MUST be in the format of a URL. | // @contact.url http://www.swagger.io/support|
|
||||
| contact.email| The email address of the contact person/organization. MUST be in the format of an email address.| // @contact.email support@swagger.io |
|
||||
| license.name | **Required.** The license name used for the API.|// @license.name Apache 2.0|
|
||||
| license.url | A URL to the license used for the API. MUST be in the format of a URL. | // @license.url http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| host | The host (name or ip) serving the API. | // @host localhost:8080 |
|
||||
| BasePath | The base path on which the API is served. | // @BasePath /api/v1 |
|
||||
| schemes | The transfer protocol for the operation that separated by spaces. | // @schemes http https |
|
||||
|
||||
## Security
|
||||
|
||||
| annotation | description | parameters | example |
|
||||
|-----------------------------------------|------------------------------------------------------------------------------------------------|-----------------------------------|--------------------------------------------------------------|
|
||||
| securitydefinitions.basic | [Basic](https://swagger.io/docs/specification/2-0/authentication/basic-authentication/) auth. | | // @securityDefinitions.basic BasicAuth |
|
||||
| securitydefinitions.apikey | [API key](https://swagger.io/docs/specification/2-0/authentication/api-keys/) auth. | in, name | // @securityDefinitions.apikey ApiKeyAuth |
|
||||
| securitydefinitions.oauth2.application | [OAuth2 application](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, scope | // @securitydefinitions.oauth2.application OAuth2Application |
|
||||
| securitydefinitions.oauth2.implicit | [OAuth2 implicit](https://swagger.io/docs/specification/authentication/oauth2/) auth. | authorizationUrl, scope | // @securitydefinitions.oauth2.implicit OAuth2Implicit |
|
||||
| securitydefinitions.oauth2.password | [OAuth2 password](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, scope | // @securitydefinitions.oauth2.password OAuth2Password |
|
||||
| securitydefinitions.oauth2.accessCode | [OAuth2 access code](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, authorizationUrl, scope | // @securitydefinitions.oauth2.accessCode OAuth2AccessCode |
|
||||
|
||||
|
||||
| parameters annotation | example |
|
||||
|-----------------------|----------------------------------------------------------|
|
||||
| in | // @in header |
|
||||
| name | // @name Authorization |
|
||||
| tokenUrl | // @tokenUrl https://example.com/oauth/token |
|
||||
| authorizationurl | // @authorizationurl https://example.com/oauth/authorize |
|
||||
| scope.hoge | // @scope.write Grants write access |
|
||||
|
||||
# API Operation
|
||||
## API Operation
|
||||
|
||||
**Example**
|
||||
[celler/controller](https://github.com/swaggo/swag/tree/master/example/celler/controller)
|
||||
@ -364,50 +338,30 @@ OPTIONS:
|
||||
| security | [Security](#security) to each API operation. |
|
||||
| success | Success response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` |
|
||||
| failure | Failure response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` |
|
||||
| header | Header in response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` |
|
||||
| router | Path definition that separated by spaces. `path`,`[httpMethod]` |
|
||||
|
||||
## Mime Types
|
||||
|
||||
| Mime Type | annotation |
|
||||
|-----------------------------------|-----------------------------------------------------------|
|
||||
| application/json | application/json, json |
|
||||
| text/xml | text/xml, xml |
|
||||
| text/plain | text/plain, plain |
|
||||
| html | text/html, html |
|
||||
| multipart/form-data | multipart/form-data, mpfd |
|
||||
| application/x-www-form-urlencoded | application/x-www-form-urlencoded, x-www-form-urlencoded |
|
||||
| application/vnd.api+json | application/vnd.api+json, json-api |
|
||||
| application/x-json-stream | application/x-json-stream, json-stream |
|
||||
| application/octet-stream | application/octet-stream, octet-stream |
|
||||
| image/png | image/png, png |
|
||||
| image/jpeg | image/jpeg, jpeg |
|
||||
| image/gif | image/gif, gif |
|
||||
`swag` accepts all MIME Types which are in the correct format, that is, match `*/*`.
|
||||
Besides that, `swag` also accepts aliases for some MIME Types as follows:
|
||||
|
||||
## Security
|
||||
| Alias | MIME Type |
|
||||
|-----------------------|-----------------------------------|
|
||||
| json | application/json |
|
||||
| xml | text/xml |
|
||||
| plain | text/plain |
|
||||
| html | text/html |
|
||||
| mpfd | multipart/form-data |
|
||||
| x-www-form-urlencoded | application/x-www-form-urlencoded |
|
||||
| json-api | application/vnd.api+json |
|
||||
| json-stream | application/x-json-stream |
|
||||
| octet-stream | application/octet-stream |
|
||||
| png | image/png |
|
||||
| jpeg | image/jpeg |
|
||||
| gif | image/gif |
|
||||
|
||||
General API info.
|
||||
|
||||
```go
|
||||
// @securityDefinitions.basic BasicAuth
|
||||
|
||||
// @securitydefinitions.oauth2.application OAuth2Application
|
||||
// @tokenUrl https://example.com/oauth/token
|
||||
// @scope.write Grants write access
|
||||
// @scope.admin Grants read and write access to administrative information
|
||||
```
|
||||
|
||||
Each API operation.
|
||||
|
||||
```go
|
||||
// @Security ApiKeyAuth
|
||||
```
|
||||
|
||||
Make it AND condition
|
||||
|
||||
```go
|
||||
// @Security ApiKeyAuth
|
||||
// @Security OAuth2Application[write, admin]
|
||||
```
|
||||
|
||||
## Param Type
|
||||
|
||||
@ -426,6 +380,26 @@ Make it AND condition
|
||||
- boolean (bool)
|
||||
- user defined struct
|
||||
|
||||
## Security
|
||||
| annotation | description | parameters | example |
|
||||
|------------|-------------|------------|---------|
|
||||
| securitydefinitions.basic | [Basic](https://swagger.io/docs/specification/2-0/authentication/basic-authentication/) auth. | | // @securityDefinitions.basic BasicAuth |
|
||||
| securitydefinitions.apikey | [API key](https://swagger.io/docs/specification/2-0/authentication/api-keys/) auth. | in, name | // @securityDefinitions.apikey ApiKeyAuth |
|
||||
| securitydefinitions.oauth2.application | [OAuth2 application](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, scope | // @securitydefinitions.oauth2.application OAuth2Application |
|
||||
| securitydefinitions.oauth2.implicit | [OAuth2 implicit](https://swagger.io/docs/specification/authentication/oauth2/) auth. | authorizationUrl, scope | // @securitydefinitions.oauth2.implicit OAuth2Implicit |
|
||||
| securitydefinitions.oauth2.password | [OAuth2 password](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, scope | // @securitydefinitions.oauth2.password OAuth2Password |
|
||||
| securitydefinitions.oauth2.accessCode | [OAuth2 access code](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, authorizationUrl, scope | // @securitydefinitions.oauth2.accessCode OAuth2AccessCode |
|
||||
|
||||
|
||||
| parameters annotation | example |
|
||||
|-----------------------|----------------------------------------------------------|
|
||||
| in | // @in header |
|
||||
| name | // @name Authorization |
|
||||
| tokenUrl | // @tokenUrl https://example.com/oauth/token |
|
||||
| authorizationurl | // @authorizationurl https://example.com/oauth/authorize |
|
||||
| scope.hoge | // @scope.write Grants write access |
|
||||
|
||||
|
||||
## Attribute
|
||||
|
||||
```go
|
||||
@ -457,12 +431,12 @@ Field Name | Type | Description
|
||||
<a name="parameterMaxLength"></a>maxLength | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.1.
|
||||
<a name="parameterMinLength"></a>minLength | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.2.
|
||||
<a name="parameterEnums"></a>enums | [\*] | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1.
|
||||
<a name="parameterFormat"></a>format | `string` | The extending format for the previously mentioned [`type`](#parameterType). See [Data Type Formats](#dataTypeFormat) for further details.
|
||||
|
||||
### Future
|
||||
|
||||
Field Name | Type | Description
|
||||
---|:---:|---
|
||||
<a name="parameterFormat"></a>format | `string` | The extending format for the previously mentioned [`type`](#parameterType). See [Data Type Formats](#dataTypeFormat) for further details.
|
||||
<a name="parameterMultipleOf"></a>multipleOf | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.1.
|
||||
<a name="parameterPattern"></a>pattern | `string` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.
|
||||
<a name="parameterMaxItems"></a>maxItems | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.2.
|
||||
@ -470,7 +444,17 @@ Field Name | Type | Description
|
||||
<a name="parameterUniqueItems"></a>uniqueItems | `boolean` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.4.
|
||||
<a name="parameterCollectionFormat"></a>collectionFormat | `string` | Determines the format of the array if type array is used. Possible values are: <ul><li>`csv` - comma separated values `foo,bar`. <li>`ssv` - space separated values `foo bar`. <li>`tsv` - tab separated values `foo\tbar`. <li>`pipes` - pipe separated values <code>foo|bar</code>. <li>`multi` - corresponds to multiple parameter instances instead of multiple values for a single instance `foo=bar&foo=baz`. This is valid only for parameters [`in`](#parameterIn) "query" or "formData". </ul> Default value is `csv`.
|
||||
|
||||
## TIPS
|
||||
## Examples
|
||||
|
||||
### Descriptions over multiple lines
|
||||
|
||||
You can add descriptions spanning multiple lines in either the general api description or routes definitions like so:
|
||||
|
||||
```go
|
||||
// @description This is the first line
|
||||
// @description This is the second line
|
||||
// @description And so forth.
|
||||
```
|
||||
|
||||
### User defined structure with an array type
|
||||
|
||||
@ -486,6 +470,13 @@ type Account struct {
|
||||
Name string `json:"name" example:"account name"`
|
||||
}
|
||||
```
|
||||
### Add a headers in response
|
||||
|
||||
```go
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Header 200 {string} Location "/entity/1"
|
||||
// @Header 200 {string} Token "qwerty"
|
||||
```
|
||||
|
||||
### Use multiple path params
|
||||
|
||||
@ -511,22 +502,129 @@ type Account struct {
|
||||
|
||||
```go
|
||||
type Account struct {
|
||||
// ID this is userid
|
||||
ID int `json:"id"
|
||||
// ID this is userid
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"` // This is Name
|
||||
}
|
||||
```
|
||||
|
||||
### Override swagger type of a struct field
|
||||
|
||||
```go
|
||||
type TimestampTime struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
///implement encoding.JSON.Marshaler interface
|
||||
func (t *TimestampTime) MarshalJSON() ([]byte, error) {
|
||||
bin := make([]byte, 16)
|
||||
bin = strconv.AppendInt(bin[:0], t.Time.Unix(), 10)
|
||||
return bin, nil
|
||||
}
|
||||
|
||||
func (t *TimestampTime) UnmarshalJSON(bin []byte) error {
|
||||
v, err := strconv.ParseInt(string(bin), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Time = time.Unix(v, 0)
|
||||
return nil
|
||||
}
|
||||
///
|
||||
|
||||
type Account struct {
|
||||
// Override primitive type by simply specifying it via `swaggertype` tag
|
||||
ID sql.NullInt64 `json:"id" swaggertype:"integer"`
|
||||
|
||||
// Override struct type to a primitive type 'integer' by specifying it via `swaggertype` tag
|
||||
RegisterTime TimestampTime `json:"register_time" swaggertype:"primitive,integer"`
|
||||
|
||||
// Array types can be overridden using "array,<prim_type>" format
|
||||
Coeffs []big.Float `json:"coeffs" swaggertype:"array,number"`
|
||||
}
|
||||
```
|
||||
|
||||
### Add extension info to struct field
|
||||
|
||||
```go
|
||||
type Account struct {
|
||||
ID int `json:"id" extensions:"x-nullable,x-abc=def"` // extensions fields must start with "x-"
|
||||
}
|
||||
```
|
||||
|
||||
generate swagger doc as follows:
|
||||
|
||||
```go
|
||||
"Account": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"x-nullable": true,
|
||||
"x-abc": "def"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### How to using security annotations
|
||||
|
||||
General API info.
|
||||
|
||||
```go
|
||||
// @securityDefinitions.basic BasicAuth
|
||||
|
||||
// @securitydefinitions.oauth2.application OAuth2Application
|
||||
// @tokenUrl https://example.com/oauth/token
|
||||
// @scope.write Grants write access
|
||||
// @scope.admin Grants read and write access to administrative information
|
||||
```
|
||||
|
||||
Each API operation.
|
||||
|
||||
```go
|
||||
// @Security ApiKeyAuth
|
||||
```
|
||||
|
||||
Make it AND condition
|
||||
|
||||
```go
|
||||
// @Security ApiKeyAuth
|
||||
// @Security OAuth2Application[write, admin]
|
||||
```
|
||||
|
||||
## 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).
|
||||
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
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||
<a href="https://github.com/swaggo/swag/graphs/contributors"><img src="https://opencollective.com/swag/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
|
||||
## Backers
|
||||
|
||||
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/swag#backer)]
|
||||
|
||||
<a href="https://opencollective.com/swag#backers" target="_blank"><img src="https://opencollective.com/swag/backers.svg?width=890"></a>
|
||||
|
||||
|
||||
## Sponsors
|
||||
|
||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/swag#sponsor)]
|
||||
|
||||
<a href="https://opencollective.com/swag/sponsor/0/website" target="_blank"><img src="https://opencollective.com/swag/sponsor/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/swag/sponsor/1/website" target="_blank"><img src="https://opencollective.com/swag/sponsor/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/swag/sponsor/2/website" target="_blank"><img src="https://opencollective.com/swag/sponsor/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/swag/sponsor/3/website" target="_blank"><img src="https://opencollective.com/swag/sponsor/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/swag/sponsor/4/website" target="_blank"><img src="https://opencollective.com/swag/sponsor/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/swag/sponsor/5/website" target="_blank"><img src="https://opencollective.com/swag/sponsor/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/swag/sponsor/6/website" target="_blank"><img src="https://opencollective.com/swag/sponsor/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/swag/sponsor/7/website" target="_blank"><img src="https://opencollective.com/swag/sponsor/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/swag/sponsor/8/website" target="_blank"><img src="https://opencollective.com/swag/sponsor/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/swag/sponsor/9/website" target="_blank"><img src="https://opencollective.com/swag/sponsor/9/avatar.svg"></a>
|
||||
|
||||
|
||||
|
||||
|
||||
## License
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fswaggo%2Fswag?ref=badge_large)
|
29
vendor/github.com/swaggo/swag/cmd/swag/main.go
generated
vendored
29
vendor/github.com/swaggo/swag/cmd/swag/main.go
generated
vendored
@ -20,18 +20,25 @@ func main() {
|
||||
Aliases: []string{"i"},
|
||||
Usage: "Create docs.go",
|
||||
Action: func(c *cli.Context) error {
|
||||
dir := c.String("dir")
|
||||
searchDir := c.String("dir")
|
||||
mainAPIFile := c.String("generalInfo")
|
||||
swaggerConfDir := c.String("swagger")
|
||||
strategy := c.String("propertyStrategy")
|
||||
outputDir := c.String("output")
|
||||
parseVendor := c.Bool("parseVendor")
|
||||
|
||||
switch strategy {
|
||||
case swag.CamelCase, swag.SnakeCase, swag.PascalCase:
|
||||
default:
|
||||
return errors.Errorf("not supported %s propertyStrategy", strategy)
|
||||
}
|
||||
|
||||
gen.New().Build(dir, mainAPIFile, swaggerConfDir, strategy)
|
||||
return nil
|
||||
return gen.New().Build(&gen.Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: mainAPIFile,
|
||||
PropNamingStrategy: strategy,
|
||||
OutputDir: outputDir,
|
||||
ParseVendor: parseVendor,
|
||||
})
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
@ -44,16 +51,20 @@ func main() {
|
||||
Value: "./",
|
||||
Usage: "Directory you want to parse",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "swagger, s",
|
||||
Value: "./docs/swagger",
|
||||
Usage: "Output the swagger conf for json and yaml",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "propertyStrategy, p",
|
||||
Value: "camelcase",
|
||||
Usage: "Property Naming Strategy like snakecase,camelcase,pascalcase",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "output, o",
|
||||
Value: "./docs",
|
||||
Usage: "Output directory for al the generated files(swagger.json, swagger.yaml and doc.go)",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "parseVendor",
|
||||
Usage: "Parse go files in 'vendor' folder, disabled by default",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
30
vendor/github.com/swaggo/swag/debug.go
generated
vendored
Normal file
30
vendor/github.com/swaggo/swag/debug.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
package swag
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
const (
|
||||
test = iota
|
||||
release
|
||||
)
|
||||
|
||||
var swagMode = release
|
||||
|
||||
func isRelease() bool {
|
||||
return swagMode == release
|
||||
}
|
||||
|
||||
//Println calls Output to print to the standard logger when release mode.
|
||||
func Println(v ...interface{}) {
|
||||
if isRelease() {
|
||||
log.Println(v...)
|
||||
}
|
||||
}
|
||||
|
||||
//Printf calls Output to print to the standard logger when release mode.
|
||||
func Printf(format string, v ...interface{}) {
|
||||
if isRelease() {
|
||||
log.Printf(format, v...)
|
||||
}
|
||||
}
|
45
vendor/github.com/swaggo/swag/gen/gen.go
generated
vendored
45
vendor/github.com/swaggo/swag/gen/gen.go
generated
vendored
@ -2,6 +2,7 @@ package gen
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
@ -22,12 +23,38 @@ func New() *Gen {
|
||||
return &Gen{}
|
||||
}
|
||||
|
||||
// Config presents Gen configurations.
|
||||
type Config struct {
|
||||
// SearchDir the swag would be parse
|
||||
SearchDir string
|
||||
|
||||
//OutputDir represents the output directory for al the generated files
|
||||
OutputDir string
|
||||
|
||||
//MainAPIFile the Go file path in which 'swagger general API Info' is written
|
||||
MainAPIFile string
|
||||
|
||||
//PropNamingStrategy represents property naming strategy like snakecase,camelcase,pascalcase
|
||||
PropNamingStrategy string
|
||||
|
||||
//ParseVendor whether swag should be parse vendor folder
|
||||
ParseVendor bool
|
||||
}
|
||||
|
||||
// Build builds swagger json file for gived searchDir and mainAPIFile. Returns json
|
||||
func (g *Gen) Build(searchDir, mainAPIFile, swaggerConfDir, propNamingStrategy string) error {
|
||||
func (g *Gen) Build(config *Config) error {
|
||||
if _, err := os.Stat(config.SearchDir); os.IsNotExist(err) {
|
||||
return fmt.Errorf("dir: %s is not exist", config.SearchDir)
|
||||
}
|
||||
|
||||
log.Println("Generate swagger docs....")
|
||||
p := swag.New()
|
||||
p.PropNamingStrategy = propNamingStrategy
|
||||
p.ParseAPI(searchDir, mainAPIFile)
|
||||
p.PropNamingStrategy = config.PropNamingStrategy
|
||||
p.ParseVendor = config.ParseVendor
|
||||
|
||||
if err := p.ParseAPI(config.SearchDir, config.MainAPIFile); err != nil {
|
||||
return err
|
||||
}
|
||||
swagger := p.GetSwagger()
|
||||
|
||||
b, err := json.MarshalIndent(swagger, "", " ")
|
||||
@ -35,15 +62,14 @@ func (g *Gen) Build(searchDir, mainAPIFile, swaggerConfDir, propNamingStrategy s
|
||||
return err
|
||||
}
|
||||
|
||||
os.MkdirAll(path.Join(searchDir, "docs"), os.ModePerm)
|
||||
docs, err := os.Create(path.Join(searchDir, "docs", "docs.go"))
|
||||
os.MkdirAll(config.OutputDir, os.ModePerm)
|
||||
docs, err := os.Create(path.Join(config.OutputDir, "docs.go"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer docs.Close()
|
||||
|
||||
os.Mkdir(swaggerConfDir, os.ModePerm)
|
||||
swaggerJSON, err := os.Create(path.Join(swaggerConfDir, "swagger.json"))
|
||||
swaggerJSON, err := os.Create(path.Join(config.OutputDir, "swagger.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -51,7 +77,7 @@ func (g *Gen) Build(searchDir, mainAPIFile, swaggerConfDir, propNamingStrategy s
|
||||
defer swaggerJSON.Close()
|
||||
swaggerJSON.Write(b)
|
||||
|
||||
swaggerYAML, err := os.Create(path.Join(swaggerConfDir, "swagger.yaml"))
|
||||
swaggerYAML, err := os.Create(path.Join(config.OutputDir, "swagger.yaml"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -75,6 +101,9 @@ func (g *Gen) Build(searchDir, mainAPIFile, swaggerConfDir, propNamingStrategy s
|
||||
}
|
||||
|
||||
log.Printf("create docs.go at %+v", docs.Name())
|
||||
log.Printf("create swagger.json at %+v", swaggerJSON.Name())
|
||||
log.Printf("create swagger.yaml at %+v", swaggerYAML.Name())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
31
vendor/github.com/swaggo/swag/go.mod
generated
vendored
Normal file
31
vendor/github.com/swaggo/swag/go.mod
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
module github.com/swaggo/swag
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect
|
||||
github.com/gin-gonic/gin v1.3.0
|
||||
github.com/go-openapi/jsonpointer v0.18.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.18.0
|
||||
github.com/go-openapi/spec v0.18.0
|
||||
github.com/go-openapi/swag v0.18.0 // indirect
|
||||
github.com/golang/protobuf v1.3.1 // indirect
|
||||
github.com/json-iterator/go v1.1.6 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe // indirect
|
||||
github.com/mattn/go-isatty v0.0.7 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/swaggo/gin-swagger v1.1.0
|
||||
github.com/ugorji/go/codec v0.0.0-20190320090025-2dc34c0b8780 // indirect
|
||||
github.com/urfave/cli v1.20.0
|
||||
golang.org/x/net v0.0.0-20190322120337-addf6b3196f6 // indirect
|
||||
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc // indirect
|
||||
golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||
)
|
106
vendor/github.com/swaggo/swag/go.sum
generated
vendored
Normal file
106
vendor/github.com/swaggo/swag/go.sum
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY=
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs=
|
||||
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
|
||||
github.com/go-openapi/jsonpointer v0.17.0 h1:nH6xp8XdXHx8dqveo0ZuJBluCO2qGrPbDNZ0dwoRHP0=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.18.0 h1:KVRzjXpMzgdM4GEMDmDTnGcY5yBwGWreJwmmk4k35yU=
|
||||
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.18.0 h1:oP2OUNdG1l2r5kYhrfVMXO54gWmzcfAwP/GFuHpNTkE=
|
||||
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/spec v0.18.0 h1:aIjeyG5mo5/FrvDkpKKEGZPmF9MPHahS72mzfVqeQXQ=
|
||||
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi880=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.18.0 h1:1DU8Km1MRGv9Pj7BNLmkA+umwTStwDHttXvx3NhJA70=
|
||||
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/swaggo/gin-swagger v1.1.0 h1:ZI6/82S07DkkrMfGKbJhKj1R+QNTICkeAJP06pU36pU=
|
||||
github.com/swaggo/gin-swagger v1.1.0/go.mod h1:FQlm07YuT1glfN3hQiO11UQ2m39vOCZ/aa3WWr5E+XU=
|
||||
github.com/swaggo/swag v1.4.0/go.mod h1:hog2WgeMOrQ/LvQ+o1YGTeT+vWVrbi0SiIslBtxKTyM=
|
||||
github.com/ugorji/go v1.1.2 h1:JON3E2/GPW2iDNGoSAusl1KDf5TRQ8k8q7Tp097pZGs=
|
||||
github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
|
||||
github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 h1:EICbibRW4JNKMcY+LsWmuwob+CRS1BmdRdjphAm9mH4=
|
||||
github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v0.0.0-20190320090025-2dc34c0b8780 h1:vG/gY/PxA3v3l04qxe3tDjXyu3bozii8ulSlIPOYKhI=
|
||||
github.com/ugorji/go/codec v0.0.0-20190320090025-2dc34c0b8780/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA=
|
||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58 h1:otZG8yDCO4LVps5+9bxOeNiCvgmOyt96J3roHTYs7oE=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190322120337-addf6b3196f6 h1:78jEq2G3J16aXneH23HSnTQQTCwMHoyO8VEiUH+bpPM=
|
||||
golang.org/x/net v0.0.0-20190322120337-addf6b3196f6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc h1:4gbWbmmPFp4ySWICouJl6emP0MyS31yy9SrTlAGFT+g=
|
||||
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190110015856-aa033095749b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89 h1:iWXXYN3edZ3Nd/7I6Rt1sXrWVmhF9bgVtlEJ7BbH124=
|
||||
golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
480
vendor/github.com/swaggo/swag/operation.go
generated
vendored
480
vendor/github.com/swaggo/swag/operation.go
generated
vendored
@ -5,7 +5,6 @@ import (
|
||||
"go/ast"
|
||||
goparser "go/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
@ -28,6 +27,23 @@ type Operation struct {
|
||||
parser *Parser
|
||||
}
|
||||
|
||||
var mimeTypeAliases = map[string]string{
|
||||
"json": "application/json",
|
||||
"xml": "text/xml",
|
||||
"plain": "text/plain",
|
||||
"html": "text/html",
|
||||
"mpfd": "multipart/form-data",
|
||||
"x-www-form-urlencoded": "application/x-www-form-urlencoded",
|
||||
"json-api": "application/vnd.api+json",
|
||||
"json-stream": "application/x-json-stream",
|
||||
"octet-stream": "application/octet-stream",
|
||||
"png": "image/png",
|
||||
"jpeg": "image/jpeg",
|
||||
"gif": "image/gif",
|
||||
}
|
||||
|
||||
var mimeTypePattern = regexp.MustCompile("^[^/]+/[^/]+$")
|
||||
|
||||
// NewOperation creates a new Operation with default properties.
|
||||
// map[int]Response
|
||||
func NewOperation() *Operation {
|
||||
@ -53,7 +69,7 @@ func (operation *Operation) ParseComment(comment string, astFile *ast.File) erro
|
||||
if operation.Description == "" {
|
||||
operation.Description = lineRemainder
|
||||
} else {
|
||||
operation.Description += "<br>" + lineRemainder
|
||||
operation.Description += "\n" + lineRemainder
|
||||
}
|
||||
case "@summary":
|
||||
operation.Summary = lineRemainder
|
||||
@ -81,28 +97,32 @@ func (operation *Operation) ParseComment(comment string, astFile *ast.File) erro
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case "@header":
|
||||
if err := operation.ParseResponseHeaderComment(lineRemainder, astFile); err != nil {
|
||||
return err
|
||||
}
|
||||
case "@router":
|
||||
if err := operation.ParseRouterComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {
|
||||
if err := operation.ParseRouterComment(lineRemainder); err != nil {
|
||||
return err
|
||||
}
|
||||
case "@security":
|
||||
if err := operation.ParseSecurityComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {
|
||||
if err := operation.ParseSecurityComment(lineRemainder); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var paramPattern = regexp.MustCompile(`(\S+)[\s]+([\w]+)[\s]+([\S.]+)[\s]+([\w]+)[\s]+"([^"]+)"`)
|
||||
|
||||
// ParseParamComment parses params return []string of param properties
|
||||
// @Param queryText form string true "The email for login"
|
||||
// [param name] [paramType] [data type] [is mandatory?] [Comment]
|
||||
// @Param some_id path int true "Some ID"
|
||||
// E.g. @Param queryText form string true "The email for login"
|
||||
// [param name] [paramType] [data type] [is mandatory?] [Comment]
|
||||
// E.g. @Param some_id path int true "Some ID"
|
||||
func (operation *Operation) ParseParamComment(commentLine string, astFile *ast.File) error {
|
||||
re := regexp.MustCompile(`([-\w]+)[\s]+([\w]+)[\s]+([\S.]+)[\s]+([\w]+)[\s]+"([^"]+)"`)
|
||||
matches := re.FindStringSubmatch(commentLine)
|
||||
matches := paramPattern.FindStringSubmatch(commentLine)
|
||||
if len(matches) != 6 {
|
||||
return fmt.Errorf("can not parse param comment \"%s\"", commentLine)
|
||||
return fmt.Errorf("missing required param comment parameters \"%s\"", commentLine)
|
||||
}
|
||||
name := matches[1]
|
||||
paramType := matches[2]
|
||||
@ -121,52 +141,68 @@ func (operation *Operation) ParseParamComment(commentLine string, astFile *ast.F
|
||||
param = createParameter(paramType, description, name, TransToValidSchemeType(schemaType), required)
|
||||
case "body":
|
||||
param = createParameter(paramType, description, name, "object", required) // TODO: if Parameter types can be objects, but also primitives and arrays
|
||||
// TODO: this snippets have to extract out
|
||||
refSplit := strings.Split(schemaType, ".")
|
||||
if len(refSplit) == 2 {
|
||||
pkgName := refSplit[0]
|
||||
typeName := refSplit[1]
|
||||
if typeSpec, ok := operation.parser.TypeDefinitions[pkgName][typeName]; ok {
|
||||
operation.parser.registerTypes[schemaType] = typeSpec
|
||||
} else {
|
||||
var typeSpec *ast.TypeSpec
|
||||
if astFile != nil {
|
||||
for _, imp := range astFile.Imports {
|
||||
if imp.Name != nil && imp.Name.Name == pkgName { // the import had an alias that matched
|
||||
break
|
||||
}
|
||||
impPath := strings.Replace(imp.Path.Value, `"`, ``, -1)
|
||||
if strings.HasSuffix(impPath, "/"+pkgName) {
|
||||
var err error
|
||||
typeSpec, err = findTypeDef(impPath, typeName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "can not find ref type: %q", schemaType)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if typeSpec == nil {
|
||||
return fmt.Errorf("can not find ref type:\"%s\"", schemaType)
|
||||
}
|
||||
|
||||
operation.parser.TypeDefinitions[pkgName][typeName] = typeSpec
|
||||
operation.parser.registerTypes[schemaType] = typeSpec
|
||||
|
||||
}
|
||||
param.Schema.Ref = spec.Ref{
|
||||
Ref: jsonreference.MustCreateRef("#/definitions/" + schemaType),
|
||||
}
|
||||
if err := operation.registerSchemaType(schemaType, astFile); err != nil {
|
||||
return err
|
||||
}
|
||||
param.Schema.Ref = spec.Ref{
|
||||
Ref: jsonreference.MustCreateRef("#/definitions/" + schemaType),
|
||||
}
|
||||
case "formData":
|
||||
param = createParameter(paramType, description, name, TransToValidSchemeType(schemaType), required)
|
||||
default:
|
||||
return fmt.Errorf("%s is not supported paramType", paramType)
|
||||
}
|
||||
|
||||
if err := operation.parseAndExtractionParamAttribute(commentLine, schemaType, ¶m); err != nil {
|
||||
return err
|
||||
}
|
||||
param = operation.parseAndExtractionParamAttribute(commentLine, schemaType, param)
|
||||
operation.Operation.Parameters = append(operation.Operation.Parameters, param)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (operation *Operation) registerSchemaType(schemaType string, astFile *ast.File) error {
|
||||
refSplit := strings.Split(schemaType, ".")
|
||||
if len(refSplit) != 2 {
|
||||
return nil
|
||||
}
|
||||
pkgName := refSplit[0]
|
||||
typeName := refSplit[1]
|
||||
if typeSpec, ok := operation.parser.TypeDefinitions[pkgName][typeName]; ok {
|
||||
operation.parser.registerTypes[schemaType] = typeSpec
|
||||
return nil
|
||||
}
|
||||
var typeSpec *ast.TypeSpec
|
||||
if astFile == nil {
|
||||
return fmt.Errorf("can not register schema type: %q reason: astFile == nil", schemaType)
|
||||
}
|
||||
for _, imp := range astFile.Imports {
|
||||
if imp.Name != nil && imp.Name.Name == pkgName { // the import had an alias that matched
|
||||
break
|
||||
}
|
||||
impPath := strings.Replace(imp.Path.Value, `"`, ``, -1)
|
||||
if strings.HasSuffix(impPath, "/"+pkgName) {
|
||||
var err error
|
||||
typeSpec, err = findTypeDef(impPath, typeName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "can not find type def: %q", schemaType)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if typeSpec == nil {
|
||||
return fmt.Errorf("can not find schema type: %q", schemaType)
|
||||
}
|
||||
|
||||
if _, ok := operation.parser.TypeDefinitions[pkgName]; !ok {
|
||||
operation.parser.TypeDefinitions[pkgName] = make(map[string]*ast.TypeSpec)
|
||||
}
|
||||
|
||||
operation.parser.TypeDefinitions[pkgName][typeName] = typeSpec
|
||||
operation.parser.registerTypes[schemaType] = typeSpec
|
||||
return nil
|
||||
}
|
||||
|
||||
var regexAttributes = map[string]*regexp.Regexp{
|
||||
// for Enums(A, B)
|
||||
"enums": regexp.MustCompile(`(?i)enums\(.*\)`),
|
||||
@ -184,99 +220,104 @@ var regexAttributes = map[string]*regexp.Regexp{
|
||||
"format": regexp.MustCompile(`(?i)format\(.*\)`),
|
||||
}
|
||||
|
||||
func (operation *Operation) parseAndExtractionParamAttribute(commentLine, schemaType string, param spec.Parameter) spec.Parameter {
|
||||
func (operation *Operation) parseAndExtractionParamAttribute(commentLine, schemaType string, param *spec.Parameter) error {
|
||||
schemaType = TransToValidSchemeType(schemaType)
|
||||
for attrKey, re := range regexAttributes {
|
||||
switch attrKey {
|
||||
case "enums":
|
||||
attr := re.FindString(commentLine)
|
||||
l := strings.Index(attr, "(")
|
||||
r := strings.Index(attr, ")")
|
||||
if !(l == -1 && r == -1) {
|
||||
enums := strings.Split(attr[l+1:r], ",")
|
||||
for _, e := range enums {
|
||||
e = strings.TrimSpace(e)
|
||||
param.Enum = append(param.Enum, defineType(schemaType, e))
|
||||
}
|
||||
enums, err := findAttrList(re, commentLine)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
for _, e := range enums {
|
||||
e = strings.TrimSpace(e)
|
||||
param.Enum = append(param.Enum, defineType(schemaType, e))
|
||||
}
|
||||
case "maxinum":
|
||||
attr := re.FindString(commentLine)
|
||||
l := strings.Index(attr, "(")
|
||||
r := strings.Index(attr, ")")
|
||||
if !(l == -1 && r == -1) {
|
||||
if schemaType != "integer" && schemaType != "number" {
|
||||
log.Panicf("maxinum is attribute to set to a number. comment=%s got=%s", commentLine, schemaType)
|
||||
}
|
||||
attr = strings.TrimSpace(attr[l+1 : r])
|
||||
n, err := strconv.ParseFloat(attr, 64)
|
||||
if err != nil {
|
||||
log.Panicf("maximum is allow only a number. comment=%s got=%s", commentLine, attr)
|
||||
}
|
||||
param.Maximum = &n
|
||||
attr, err := findAttr(re, commentLine)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if schemaType != "integer" && schemaType != "number" {
|
||||
return fmt.Errorf("maxinum is attribute to set to a number. comment=%s got=%s", commentLine, schemaType)
|
||||
}
|
||||
n, err := strconv.ParseFloat(attr, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("maximum is allow only a number. comment=%s got=%s", commentLine, attr)
|
||||
}
|
||||
param.Maximum = &n
|
||||
case "mininum":
|
||||
attr := re.FindString(commentLine)
|
||||
l := strings.Index(attr, "(")
|
||||
r := strings.Index(attr, ")")
|
||||
if !(l == -1 && r == -1) {
|
||||
if schemaType != "integer" && schemaType != "number" {
|
||||
log.Panicf("mininum is attribute to set to a number. comment=%s got=%s", commentLine, schemaType)
|
||||
}
|
||||
attr = strings.TrimSpace(attr[l+1 : r])
|
||||
n, err := strconv.ParseFloat(attr, 64)
|
||||
if err != nil {
|
||||
log.Panicf("mininum is allow only a number got=%s", attr)
|
||||
}
|
||||
param.Minimum = &n
|
||||
attr, err := findAttr(re, commentLine)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if schemaType != "integer" && schemaType != "number" {
|
||||
return fmt.Errorf("mininum is attribute to set to a number. comment=%s got=%s", commentLine, schemaType)
|
||||
}
|
||||
n, err := strconv.ParseFloat(attr, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("mininum is allow only a number got=%s", attr)
|
||||
}
|
||||
param.Minimum = &n
|
||||
case "default":
|
||||
attr := re.FindString(commentLine)
|
||||
l := strings.Index(attr, "(")
|
||||
r := strings.Index(attr, ")")
|
||||
if !(l == -1 && r == -1) {
|
||||
attr = strings.TrimSpace(attr[l+1 : r])
|
||||
param.Default = defineType(schemaType, attr)
|
||||
attr, err := findAttr(re, commentLine)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
param.Default = defineType(schemaType, attr)
|
||||
case "maxlength":
|
||||
attr := re.FindString(commentLine)
|
||||
l := strings.Index(attr, "(")
|
||||
r := strings.Index(attr, ")")
|
||||
if !(l == -1 && r == -1) {
|
||||
if schemaType != "string" {
|
||||
log.Panicf("maxlength is attribute to set to a number. comment=%s got=%s", commentLine, schemaType)
|
||||
}
|
||||
attr = strings.TrimSpace(attr[l+1 : r])
|
||||
n, err := strconv.ParseInt(attr, 10, 64)
|
||||
if err != nil {
|
||||
log.Panicf("maxlength is allow only a number got=%s", attr)
|
||||
}
|
||||
param.MaxLength = &n
|
||||
attr, err := findAttr(re, commentLine)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if schemaType != "string" {
|
||||
return fmt.Errorf("maxlength is attribute to set to a number. comment=%s got=%s", commentLine, schemaType)
|
||||
}
|
||||
n, err := strconv.ParseInt(attr, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("maxlength is allow only a number got=%s", attr)
|
||||
}
|
||||
param.MaxLength = &n
|
||||
case "minlength":
|
||||
attr := re.FindString(commentLine)
|
||||
l := strings.Index(attr, "(")
|
||||
r := strings.Index(attr, ")")
|
||||
if !(l == -1 && r == -1) {
|
||||
if schemaType != "string" {
|
||||
log.Panicf("maxlength is attribute to set to a number. comment=%s got=%s", commentLine, schemaType)
|
||||
}
|
||||
attr = strings.TrimSpace(attr[l+1 : r])
|
||||
n, err := strconv.ParseInt(attr, 10, 64)
|
||||
if err != nil {
|
||||
log.Panicf("minlength is allow only a number got=%s", attr)
|
||||
}
|
||||
param.MinLength = &n
|
||||
attr, err := findAttr(re, commentLine)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if schemaType != "string" {
|
||||
return fmt.Errorf("maxlength is attribute to set to a number. comment=%s got=%s", commentLine, schemaType)
|
||||
}
|
||||
n, err := strconv.ParseInt(attr, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("minlength is allow only a number got=%s", attr)
|
||||
}
|
||||
param.MinLength = &n
|
||||
case "format":
|
||||
attr := re.FindString(commentLine)
|
||||
l := strings.Index(attr, "(")
|
||||
r := strings.Index(attr, ")")
|
||||
if !(l == -1 && r == -1) {
|
||||
param.Format = strings.TrimSpace(attr[l+1 : r])
|
||||
attr, err := findAttr(re, commentLine)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
param.Format = attr
|
||||
}
|
||||
}
|
||||
return param
|
||||
return nil
|
||||
}
|
||||
|
||||
func findAttr(re *regexp.Regexp, commentLine string) (string, error) {
|
||||
attr := re.FindString(commentLine)
|
||||
l := strings.Index(attr, "(")
|
||||
r := strings.Index(attr, ")")
|
||||
if l == -1 || r == -1 {
|
||||
return "", fmt.Errorf("can not find regex=%s, comment=%s", re.String(), commentLine)
|
||||
}
|
||||
return strings.TrimSpace(attr[l+1 : r]), nil
|
||||
}
|
||||
|
||||
func findAttrList(re *regexp.Regexp, commentLine string) ([]string, error) {
|
||||
attr, err := findAttr(re, commentLine)
|
||||
if err != nil {
|
||||
return []string{""}, err
|
||||
}
|
||||
return strings.Split(attr, ","), nil
|
||||
}
|
||||
|
||||
// defineType enum value define the type (object and array unsupported)
|
||||
@ -318,82 +359,40 @@ func (operation *Operation) ParseTagsComment(commentLine string) {
|
||||
|
||||
// ParseAcceptComment parses comment for given `accept` comment string.
|
||||
func (operation *Operation) ParseAcceptComment(commentLine string) error {
|
||||
accepts := strings.Split(commentLine, ",")
|
||||
for _, a := range accepts {
|
||||
switch a {
|
||||
case "json", "application/json":
|
||||
operation.Consumes = append(operation.Consumes, "application/json")
|
||||
case "xml", "text/xml":
|
||||
operation.Consumes = append(operation.Consumes, "text/xml")
|
||||
case "plain", "text/plain":
|
||||
operation.Consumes = append(operation.Consumes, "text/plain")
|
||||
case "html", "text/html":
|
||||
operation.Consumes = append(operation.Consumes, "text/html")
|
||||
case "mpfd", "multipart/form-data":
|
||||
operation.Consumes = append(operation.Consumes, "multipart/form-data")
|
||||
case "x-www-form-urlencoded", "application/x-www-form-urlencoded":
|
||||
operation.Consumes = append(operation.Consumes, "application/x-www-form-urlencoded")
|
||||
case "json-api", "application/vnd.api+json":
|
||||
operation.Consumes = append(operation.Consumes, "application/vnd.api+json")
|
||||
case "json-stream", "application/x-json-stream":
|
||||
operation.Consumes = append(operation.Consumes, "application/x-json-stream")
|
||||
case "octet-stream", "application/octet-stream":
|
||||
operation.Consumes = append(operation.Consumes, "application/octet-stream")
|
||||
case "png", "image/png":
|
||||
operation.Consumes = append(operation.Consumes, "image/png")
|
||||
case "jpeg", "image/jpeg":
|
||||
operation.Consumes = append(operation.Consumes, "image/jpeg")
|
||||
case "gif", "image/gif":
|
||||
operation.Consumes = append(operation.Consumes, "image/gif")
|
||||
default:
|
||||
return fmt.Errorf("%v accept type can't accepted", a)
|
||||
return parseMimeTypeList(commentLine, &operation.Consumes, "%v accept type can't be accepted")
|
||||
}
|
||||
|
||||
// ParseProduceComment parses comment for given `produce` comment string.
|
||||
func (operation *Operation) ParseProduceComment(commentLine string) error {
|
||||
return parseMimeTypeList(commentLine, &operation.Produces, "%v produce type can't be accepted")
|
||||
}
|
||||
|
||||
// parseMimeTypeList parses a list of MIME Types for a comment like
|
||||
// `produce` (`Content-Type:` response header) or
|
||||
// `accept` (`Accept:` request header)
|
||||
func parseMimeTypeList(mimeTypeList string, typeList *[]string, format string) error {
|
||||
mimeTypes := strings.Split(mimeTypeList, ",")
|
||||
for _, typeName := range mimeTypes {
|
||||
if mimeTypePattern.MatchString(typeName) {
|
||||
*typeList = append(*typeList, typeName)
|
||||
continue
|
||||
}
|
||||
if aliasMimeType, ok := mimeTypeAliases[typeName]; ok {
|
||||
*typeList = append(*typeList, aliasMimeType)
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf(format, typeName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseProduceComment parses comment for gived `produce` comment string.
|
||||
func (operation *Operation) ParseProduceComment(commentLine string) error {
|
||||
produces := strings.Split(commentLine, ",")
|
||||
for _, a := range produces {
|
||||
switch a {
|
||||
case "json", "application/json":
|
||||
operation.Produces = append(operation.Produces, "application/json")
|
||||
case "xml", "text/xml":
|
||||
operation.Produces = append(operation.Produces, "text/xml")
|
||||
case "plain", "text/plain":
|
||||
operation.Produces = append(operation.Produces, "text/plain")
|
||||
case "html", "text/html":
|
||||
operation.Produces = append(operation.Produces, "text/html")
|
||||
case "mpfd", "multipart/form-data":
|
||||
operation.Produces = append(operation.Produces, "multipart/form-data")
|
||||
case "x-www-form-urlencoded", "application/x-www-form-urlencoded":
|
||||
operation.Produces = append(operation.Produces, "application/x-www-form-urlencoded")
|
||||
case "json-api", "application/vnd.api+json":
|
||||
operation.Produces = append(operation.Produces, "application/vnd.api+json")
|
||||
case "json-stream", "application/x-json-stream":
|
||||
operation.Produces = append(operation.Produces, "application/x-json-stream")
|
||||
case "octet-stream", "application/octet-stream":
|
||||
operation.Produces = append(operation.Produces, "application/octet-stream")
|
||||
case "png", "image/png":
|
||||
operation.Produces = append(operation.Produces, "image/png")
|
||||
case "jpeg", "image/jpeg":
|
||||
operation.Produces = append(operation.Produces, "image/jpeg")
|
||||
case "gif", "image/gif":
|
||||
operation.Produces = append(operation.Produces, "image/gif")
|
||||
default:
|
||||
return fmt.Errorf("%v produce type can't accepted", a)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var routerPattern = regexp.MustCompile(`([\w\.\/\-{}\+]+)[^\[]+\[([^\]]+)`)
|
||||
|
||||
// ParseRouterComment parses comment for gived `router` comment string.
|
||||
func (operation *Operation) ParseRouterComment(commentLine string) error {
|
||||
re := regexp.MustCompile(`([\w\.\/\-{}\+]+)[^\[]+\[([^\]]+)`)
|
||||
var matches []string
|
||||
|
||||
if matches = re.FindStringSubmatch(commentLine); len(matches) != 3 {
|
||||
if matches = routerPattern.FindStringSubmatch(commentLine); len(matches) != 3 {
|
||||
return fmt.Errorf("can not parse router comment \"%s\"", commentLine)
|
||||
}
|
||||
path := matches[1]
|
||||
@ -433,6 +432,7 @@ func (operation *Operation) ParseSecurityComment(commentLine string) error {
|
||||
|
||||
// findTypeDef attempts to find the *ast.TypeSpec for a specific type given the
|
||||
// type's name and the package's import path
|
||||
// TODO: improve finding external pkg
|
||||
func findTypeDef(importPath, typeName string) (*ast.TypeSpec, error) {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
@ -485,12 +485,13 @@ func findTypeDef(importPath, typeName string) (*ast.TypeSpec, error) {
|
||||
return nil, errors.New("type spec not found")
|
||||
}
|
||||
|
||||
var responsePattern = regexp.MustCompile(`([\d]+)[\s]+([\w\{\}]+)[\s]+([\w\-\.\/]+)[^"]*(.*)?`)
|
||||
|
||||
// ParseResponseComment parses comment for gived `response` comment string.
|
||||
func (operation *Operation) ParseResponseComment(commentLine string, astFile *ast.File) error {
|
||||
re := regexp.MustCompile(`([\d]+)[\s]+([\w\{\}]+)[\s]+([\w\-\.\/]+)[^"]*(.*)?`)
|
||||
var matches []string
|
||||
|
||||
if matches = re.FindStringSubmatch(commentLine); len(matches) != 5 {
|
||||
if matches = responsePattern.FindStringSubmatch(commentLine); len(matches) != 5 {
|
||||
return fmt.Errorf("can not parse response comment \"%s\"", commentLine)
|
||||
}
|
||||
|
||||
@ -508,46 +509,8 @@ func (operation *Operation) ParseResponseComment(commentLine string, astFile *as
|
||||
refType := matches[3]
|
||||
|
||||
if operation.parser != nil { // checking refType has existing in 'TypeDefinitions'
|
||||
refSplit := strings.Split(refType, ".")
|
||||
if len(refSplit) == 2 {
|
||||
pkgName := refSplit[0]
|
||||
typeName := refSplit[1]
|
||||
|
||||
if typeSpec, ok := operation.parser.TypeDefinitions[pkgName][typeName]; ok {
|
||||
operation.parser.registerTypes[refType] = typeSpec
|
||||
} else {
|
||||
var typeSpec *ast.TypeSpec
|
||||
if astFile != nil {
|
||||
for _, imp := range astFile.Imports {
|
||||
if imp.Name != nil && imp.Name.Name == pkgName { // the import had an alias that matched
|
||||
break
|
||||
}
|
||||
impPath := strings.Replace(imp.Path.Value, `"`, ``, -1)
|
||||
|
||||
if strings.HasSuffix(impPath, "/"+pkgName) {
|
||||
var err error
|
||||
|
||||
typeSpec, err = findTypeDef(impPath, typeName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "can not find ref type: %q", refType)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if typeSpec == nil {
|
||||
return fmt.Errorf("can not find ref type: %q", refType)
|
||||
}
|
||||
|
||||
if _, ok := operation.parser.TypeDefinitions[pkgName]; !ok {
|
||||
operation.parser.TypeDefinitions[pkgName] = make(map[string]*ast.TypeSpec)
|
||||
|
||||
}
|
||||
operation.parser.TypeDefinitions[pkgName][typeName] = typeSpec
|
||||
operation.parser.registerTypes[refType] = typeSpec
|
||||
}
|
||||
|
||||
if err := operation.registerSchemaType(refType, astFile); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -595,12 +558,59 @@ func (operation *Operation) ParseResponseComment(commentLine string, astFile *as
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseEmptyResponseComment parse only comment out status code and description,eg: @Success 200 "it's ok"
|
||||
func (operation *Operation) ParseEmptyResponseComment(commentLine string) error {
|
||||
re := regexp.MustCompile(`([\d]+)[\s]+"(.*)"`)
|
||||
// ParseResponseHeaderComment parses comment for gived `response header` comment string.
|
||||
func (operation *Operation) ParseResponseHeaderComment(commentLine string, astFile *ast.File) error {
|
||||
var matches []string
|
||||
|
||||
if matches = re.FindStringSubmatch(commentLine); len(matches) != 3 {
|
||||
if matches = responsePattern.FindStringSubmatch(commentLine); len(matches) != 5 {
|
||||
return fmt.Errorf("can not parse response comment \"%s\"", commentLine)
|
||||
}
|
||||
|
||||
response := spec.Response{}
|
||||
|
||||
code, _ := strconv.Atoi(matches[1])
|
||||
|
||||
responseDescription := strings.Trim(matches[4], "\"")
|
||||
if responseDescription == "" {
|
||||
responseDescription = http.StatusText(code)
|
||||
}
|
||||
response.Description = responseDescription
|
||||
|
||||
schemaType := strings.Trim(matches[2], "{}")
|
||||
refType := matches[3]
|
||||
|
||||
if operation.Responses == nil {
|
||||
operation.Responses = &spec.Responses{
|
||||
ResponsesProps: spec.ResponsesProps{
|
||||
StatusCodeResponses: make(map[int]spec.Response),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
response, responseExist := operation.Responses.StatusCodeResponses[code]
|
||||
if responseExist {
|
||||
header := spec.Header{}
|
||||
header.Description = responseDescription
|
||||
header.Type = schemaType
|
||||
|
||||
if response.Headers == nil {
|
||||
response.Headers = make(map[string]spec.Header)
|
||||
}
|
||||
response.Headers[refType] = header
|
||||
|
||||
operation.Responses.StatusCodeResponses[code] = response
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var emptyResponsePattern = regexp.MustCompile(`([\d]+)[\s]+"(.*)"`)
|
||||
|
||||
// ParseEmptyResponseComment parse only comment out status code and description,eg: @Success 200 "it's ok"
|
||||
func (operation *Operation) ParseEmptyResponseComment(commentLine string) error {
|
||||
var matches []string
|
||||
|
||||
if matches = emptyResponsePattern.FindStringSubmatch(commentLine); len(matches) != 3 {
|
||||
return fmt.Errorf("can not parse response comment \"%s\"", commentLine)
|
||||
}
|
||||
|
||||
|
394
vendor/github.com/swaggo/swag/parser.go
generated
vendored
394
vendor/github.com/swaggo/swag/parser.go
generated
vendored
@ -5,7 +5,6 @@ import (
|
||||
"go/ast"
|
||||
goparser "go/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
@ -51,6 +50,8 @@ type Parser struct {
|
||||
|
||||
PropNamingStrategy string
|
||||
|
||||
ParseVendor bool
|
||||
|
||||
// structStack stores full names of the structures that were already parsed or are being parsed now
|
||||
structStack []string
|
||||
}
|
||||
@ -82,7 +83,7 @@ func New() *Parser {
|
||||
|
||||
// ParseAPI parses general api info for gived searchDir and mainAPIFile
|
||||
func (parser *Parser) ParseAPI(searchDir string, mainAPIFile string) error {
|
||||
log.Println("Generate general API Info")
|
||||
Println("Generate general API Info")
|
||||
if err := parser.getAllGoFileInfo(searchDir); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -92,8 +93,10 @@ func (parser *Parser) ParseAPI(searchDir string, mainAPIFile string) error {
|
||||
parser.ParseType(astFile)
|
||||
}
|
||||
|
||||
for _, astFile := range parser.files {
|
||||
parser.ParseRouterAPIInfo(astFile)
|
||||
for fileName, astFile := range parser.files {
|
||||
if err := parser.ParseRouterAPIInfo(fileName, astFile); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
parser.ParseDefinitions()
|
||||
@ -122,15 +125,24 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
if fileTree.Comments != nil {
|
||||
for _, comment := range fileTree.Comments {
|
||||
comments := strings.Split(comment.Text(), "\n")
|
||||
previousAttribute := ""
|
||||
for _, commentLine := range comments {
|
||||
attribute := strings.ToLower(strings.Split(commentLine, " ")[0])
|
||||
multilineBlock := false
|
||||
if previousAttribute == attribute {
|
||||
multilineBlock = true
|
||||
}
|
||||
switch attribute {
|
||||
case "@version":
|
||||
parser.swagger.Info.Version = strings.TrimSpace(commentLine[len(attribute):])
|
||||
case "@title":
|
||||
parser.swagger.Info.Title = strings.TrimSpace(commentLine[len(attribute):])
|
||||
case "@description":
|
||||
parser.swagger.Info.Description = strings.TrimSpace(commentLine[len(attribute):])
|
||||
if parser.swagger.Info.Description == "{{.Description}}" {
|
||||
parser.swagger.Info.Description = strings.TrimSpace(commentLine[len(attribute):])
|
||||
} else if multilineBlock {
|
||||
parser.swagger.Info.Description += "\n" + strings.TrimSpace(commentLine[len(attribute):])
|
||||
}
|
||||
case "@termsofservice":
|
||||
parser.swagger.Info.TermsOfService = strings.TrimSpace(commentLine[len(attribute):])
|
||||
case "@contact.name":
|
||||
@ -148,7 +160,7 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
case "@basepath":
|
||||
parser.swagger.BasePath = strings.TrimSpace(commentLine[len(attribute):])
|
||||
case "@schemes":
|
||||
parser.swagger.Schemes = GetSchemes(commentLine)
|
||||
parser.swagger.Schemes = getSchemes(commentLine)
|
||||
case "@tag.name":
|
||||
commentInfo := strings.TrimSpace(commentLine[len(attribute):])
|
||||
parser.swagger.Tags = append(parser.swagger.Tags, spec.Tag{
|
||||
@ -173,11 +185,12 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
commentInfo := strings.TrimSpace(commentLine[len(attribute):])
|
||||
tag := parser.swagger.Tags[len(parser.swagger.Tags)-1]
|
||||
if tag.TagProps.ExternalDocs == nil {
|
||||
log.Panic("@tag.docs.description needs to come after a @tags.docs.url")
|
||||
return errors.New("@tag.docs.description needs to come after a @tags.docs.url")
|
||||
}
|
||||
tag.TagProps.ExternalDocs.Description = commentInfo
|
||||
replaceLastTag(parser.swagger.Tags, tag)
|
||||
}
|
||||
previousAttribute = attribute
|
||||
}
|
||||
|
||||
for i := 0; i < len(comments); i++ {
|
||||
@ -198,7 +211,7 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
}
|
||||
}
|
||||
if len(attrMap) != 2 {
|
||||
log.Panic("@securitydefinitions.apikey is @name and @in required")
|
||||
return errors.New("@securitydefinitions.apikey is @name and @in required")
|
||||
}
|
||||
securityMap[strings.TrimSpace(comments[i][len(attribute):])] = spec.APIKeyAuth(attrMap["@name"], attrMap["@in"])
|
||||
case "@securitydefinitions.oauth2.application":
|
||||
@ -208,8 +221,18 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
securityAttr := strings.ToLower(strings.Split(v, " ")[0])
|
||||
if securityAttr == "@tokenurl" {
|
||||
attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):])
|
||||
} else if isExistsScope(securityAttr) {
|
||||
scopes[getScopeScheme(securityAttr)] = v[len(securityAttr):]
|
||||
} else {
|
||||
isExists, err := isExistsScope(securityAttr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isExists {
|
||||
scopScheme, err := getScopeScheme(securityAttr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scopes[scopScheme] = v[len(securityAttr):]
|
||||
}
|
||||
}
|
||||
// next securityDefinitions
|
||||
if strings.Index(securityAttr, "@securitydefinitions.") == 0 {
|
||||
@ -217,7 +240,7 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
}
|
||||
}
|
||||
if len(attrMap) != 1 {
|
||||
log.Panic("@securitydefinitions.oauth2.application is @tokenUrl required")
|
||||
return errors.New("@securitydefinitions.oauth2.application is @tokenUrl required")
|
||||
}
|
||||
securityScheme := spec.OAuth2Application(attrMap["@tokenurl"])
|
||||
for scope, description := range scopes {
|
||||
@ -231,8 +254,18 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
securityAttr := strings.ToLower(strings.Split(v, " ")[0])
|
||||
if securityAttr == "@authorizationurl" {
|
||||
attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):])
|
||||
} else if isExistsScope(securityAttr) {
|
||||
scopes[getScopeScheme(securityAttr)] = v[len(securityAttr):]
|
||||
} else {
|
||||
isExists, err := isExistsScope(securityAttr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isExists {
|
||||
scopScheme, err := getScopeScheme(securityAttr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scopes[scopScheme] = v[len(securityAttr):]
|
||||
}
|
||||
}
|
||||
// next securityDefinitions
|
||||
if strings.Index(securityAttr, "@securitydefinitions.") == 0 {
|
||||
@ -240,7 +273,7 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
}
|
||||
}
|
||||
if len(attrMap) != 1 {
|
||||
log.Panic("@securitydefinitions.oauth2.implicit is @authorizationUrl required")
|
||||
return errors.New("@securitydefinitions.oauth2.implicit is @authorizationUrl required")
|
||||
}
|
||||
securityScheme := spec.OAuth2Implicit(attrMap["@authorizationurl"])
|
||||
for scope, description := range scopes {
|
||||
@ -254,8 +287,18 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
securityAttr := strings.ToLower(strings.Split(v, " ")[0])
|
||||
if securityAttr == "@tokenurl" {
|
||||
attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):])
|
||||
} else if isExistsScope(securityAttr) {
|
||||
scopes[getScopeScheme(securityAttr)] = v[len(securityAttr):]
|
||||
} else {
|
||||
isExists, err := isExistsScope(securityAttr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isExists {
|
||||
scopScheme, err := getScopeScheme(securityAttr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scopes[scopScheme] = v[len(securityAttr):]
|
||||
}
|
||||
}
|
||||
// next securityDefinitions
|
||||
if strings.Index(securityAttr, "@securitydefinitions.") == 0 {
|
||||
@ -263,7 +306,7 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
}
|
||||
}
|
||||
if len(attrMap) != 1 {
|
||||
log.Panic("@securitydefinitions.oauth2.password is @tokenUrl required")
|
||||
return errors.New("@securitydefinitions.oauth2.password is @tokenUrl required")
|
||||
}
|
||||
securityScheme := spec.OAuth2Password(attrMap["@tokenurl"])
|
||||
for scope, description := range scopes {
|
||||
@ -277,8 +320,18 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
securityAttr := strings.ToLower(strings.Split(v, " ")[0])
|
||||
if securityAttr == "@tokenurl" || securityAttr == "@authorizationurl" {
|
||||
attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):])
|
||||
} else if isExistsScope(securityAttr) {
|
||||
scopes[getScopeScheme(securityAttr)] = v[len(securityAttr):]
|
||||
} else {
|
||||
isExists, err := isExistsScope(securityAttr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isExists {
|
||||
scopScheme, err := getScopeScheme(securityAttr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scopes[scopScheme] = v[len(securityAttr):]
|
||||
}
|
||||
}
|
||||
// next securityDefinitions
|
||||
if strings.Index(securityAttr, "@securitydefinitions.") == 0 {
|
||||
@ -286,7 +339,7 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
}
|
||||
}
|
||||
if len(attrMap) != 2 {
|
||||
log.Panic("@securitydefinitions.oauth2.accessCode is @tokenUrl and @authorizationUrl required")
|
||||
return errors.New("@securitydefinitions.oauth2.accessCode is @tokenUrl and @authorizationUrl required")
|
||||
}
|
||||
securityScheme := spec.OAuth2AccessToken(attrMap["@authorizationurl"], attrMap["@tokenurl"])
|
||||
for scope, description := range scopes {
|
||||
@ -304,34 +357,34 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getScopeScheme(scope string) string {
|
||||
func getScopeScheme(scope string) (string, error) {
|
||||
scopeValue := scope[strings.Index(scope, "@scope."):]
|
||||
if scopeValue == "" {
|
||||
panic("@scope is empty")
|
||||
return "", errors.New("@scope is empty")
|
||||
}
|
||||
return scope[len("@scope."):]
|
||||
return scope[len("@scope."):], nil
|
||||
}
|
||||
|
||||
func isExistsScope(scope string) bool {
|
||||
func isExistsScope(scope string) (bool, error) {
|
||||
s := strings.Fields(scope)
|
||||
for _, v := range s {
|
||||
if strings.Index(v, "@scope.") != -1 {
|
||||
if strings.Index(v, ",") != -1 {
|
||||
panic("@scope can't use comma(,) get=" + v)
|
||||
return false, fmt.Errorf("@scope can't use comma(,) get=" + v)
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Index(scope, "@scope.") != -1
|
||||
return strings.Index(scope, "@scope.") != -1, nil
|
||||
}
|
||||
|
||||
// GetSchemes parses swagger schemes for given commentLine
|
||||
func GetSchemes(commentLine string) []string {
|
||||
// getSchemes parses swagger schemes for given commentLine
|
||||
func getSchemes(commentLine string) []string {
|
||||
attribute := strings.ToLower(strings.Split(commentLine, " ")[0])
|
||||
return strings.Split(strings.TrimSpace(commentLine[len(attribute):]), " ")
|
||||
}
|
||||
|
||||
// ParseRouterAPIInfo parses router api info for given astFile
|
||||
func (parser *Parser) ParseRouterAPIInfo(astFile *ast.File) {
|
||||
func (parser *Parser) ParseRouterAPIInfo(fileName string, astFile *ast.File) error {
|
||||
for _, astDescription := range astFile.Decls {
|
||||
switch astDeclaration := astDescription.(type) {
|
||||
case *ast.FuncDecl:
|
||||
@ -340,7 +393,7 @@ func (parser *Parser) ParseRouterAPIInfo(astFile *ast.File) {
|
||||
operation.parser = parser
|
||||
for _, comment := range astDeclaration.Doc.List {
|
||||
if err := operation.ParseComment(comment.Text, astFile); err != nil {
|
||||
log.Panicf("ParseComment panic:%+v", err)
|
||||
return fmt.Errorf("ParseComment error in file %s :%+v", fileName, err)
|
||||
}
|
||||
}
|
||||
var pathItem spec.PathItem
|
||||
@ -370,6 +423,8 @@ func (parser *Parser) ParseRouterAPIInfo(astFile *ast.File) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseType parses type info for given astFile.
|
||||
@ -407,7 +462,15 @@ func (parser *Parser) isInStructStack(refTypeName string) bool {
|
||||
|
||||
// ParseDefinitions parses Swagger Api definitions.
|
||||
func (parser *Parser) ParseDefinitions() {
|
||||
for refTypeName, typeSpec := range parser.registerTypes {
|
||||
// sort the typeNames so that parsing definitions is deterministic
|
||||
typeNames := make([]string, 0, len(parser.registerTypes))
|
||||
for refTypeName := range parser.registerTypes {
|
||||
typeNames = append(typeNames, refTypeName)
|
||||
}
|
||||
sort.Strings(typeNames)
|
||||
|
||||
for _, refTypeName := range typeNames {
|
||||
typeSpec := parser.registerTypes[refTypeName]
|
||||
ss := strings.Split(refTypeName, ".")
|
||||
pkgName := ss[0]
|
||||
parser.structStack = nil
|
||||
@ -418,24 +481,30 @@ func (parser *Parser) ParseDefinitions() {
|
||||
// ParseDefinition parses given type spec that corresponds to the type under
|
||||
// given name and package, and populates swagger schema definitions registry
|
||||
// with a schema for the given type
|
||||
func (parser *Parser) ParseDefinition(pkgName, typeName string, typeSpec *ast.TypeSpec) {
|
||||
func (parser *Parser) ParseDefinition(pkgName, typeName string, typeSpec *ast.TypeSpec) error {
|
||||
refTypeName := fullTypeName(pkgName, typeName)
|
||||
if _, isParsed := parser.swagger.Definitions[refTypeName]; isParsed {
|
||||
log.Println("Skipping '" + refTypeName + "', already parsed.")
|
||||
return
|
||||
Println("Skipping '" + refTypeName + "', already parsed.")
|
||||
return nil
|
||||
}
|
||||
|
||||
if parser.isInStructStack(refTypeName) {
|
||||
log.Println("Skipping '" + refTypeName + "', recursion detected.")
|
||||
return
|
||||
Println("Skipping '" + refTypeName + "', recursion detected.")
|
||||
return nil
|
||||
}
|
||||
parser.structStack = append(parser.structStack, refTypeName)
|
||||
|
||||
log.Println("Generating " + refTypeName)
|
||||
parser.swagger.Definitions[refTypeName] = parser.parseTypeExpr(pkgName, typeName, typeSpec.Type, true)
|
||||
Println("Generating " + refTypeName)
|
||||
|
||||
schema, err := parser.parseTypeExpr(pkgName, typeName, typeSpec.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parser.swagger.Definitions[refTypeName] = schema
|
||||
return nil
|
||||
}
|
||||
|
||||
func (parser *Parser) collectRequiredFields(pkgName string, properties map[string]spec.Schema) (requiredFields []string) {
|
||||
func (parser *Parser) collectRequiredFields(pkgName string, properties map[string]spec.Schema, extraRequired []string) (requiredFields []string) {
|
||||
// created sorted list of properties keys so when we iterate over them it's deterministic
|
||||
ks := make([]string, 0, len(properties))
|
||||
for k := range properties {
|
||||
@ -461,6 +530,12 @@ func (parser *Parser) collectRequiredFields(pkgName string, properties map[strin
|
||||
properties[k] = prop
|
||||
}
|
||||
|
||||
if extraRequired != nil {
|
||||
requiredFields = append(requiredFields, extraRequired...)
|
||||
}
|
||||
|
||||
sort.Strings(requiredFields)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -473,22 +548,35 @@ func fullTypeName(pkgName, typeName string) string {
|
||||
|
||||
// parseTypeExpr parses given type expression that corresponds to the type under
|
||||
// given name and package, and returns swagger schema for it.
|
||||
func (parser *Parser) parseTypeExpr(pkgName, typeName string, typeExpr ast.Expr, flattenRequired bool) spec.Schema {
|
||||
func (parser *Parser) parseTypeExpr(pkgName, typeName string, typeExpr ast.Expr) (spec.Schema, error) {
|
||||
//TODO: return pointer to spec.Schema
|
||||
|
||||
switch expr := typeExpr.(type) {
|
||||
// type Foo struct {...}
|
||||
case *ast.StructType:
|
||||
refTypeName := fullTypeName(pkgName, typeName)
|
||||
if schema, isParsed := parser.swagger.Definitions[refTypeName]; isParsed {
|
||||
return schema
|
||||
return schema, nil
|
||||
}
|
||||
|
||||
extraRequired := make([]string, 0)
|
||||
properties := make(map[string]spec.Schema)
|
||||
for _, field := range expr.Fields.List {
|
||||
var fieldProps map[string]spec.Schema
|
||||
var requiredFromAnon []string
|
||||
if field.Names == nil {
|
||||
fieldProps = parser.parseAnonymousField(pkgName, field)
|
||||
var err error
|
||||
fieldProps, requiredFromAnon, err = parser.parseAnonymousField(pkgName, field)
|
||||
if err != nil {
|
||||
return spec.Schema{}, err
|
||||
}
|
||||
extraRequired = append(extraRequired, requiredFromAnon...)
|
||||
} else {
|
||||
fieldProps = parser.parseStruct(pkgName, field)
|
||||
var err error
|
||||
fieldProps, err = parser.parseStruct(pkgName, field)
|
||||
if err != nil {
|
||||
return spec.Schema{}, err
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range fieldProps {
|
||||
@ -496,17 +584,16 @@ func (parser *Parser) parseTypeExpr(pkgName, typeName string, typeExpr ast.Expr,
|
||||
}
|
||||
}
|
||||
|
||||
required := parser.collectRequiredFields(pkgName, properties)
|
||||
// collect requireds from our properties and anonymous fields
|
||||
required := parser.collectRequiredFields(pkgName, properties, extraRequired)
|
||||
|
||||
// unset required from properties because we've aggregated them
|
||||
if flattenRequired {
|
||||
for k, prop := range properties {
|
||||
tname := prop.SchemaProps.Type[0]
|
||||
if tname != "object" {
|
||||
prop.SchemaProps.Required = make([]string, 0)
|
||||
}
|
||||
properties[k] = prop
|
||||
// unset required from properties because we've collected them
|
||||
for k, prop := range properties {
|
||||
tname := prop.SchemaProps.Type[0]
|
||||
if tname != "object" {
|
||||
prop.SchemaProps.Required = make([]string, 0)
|
||||
}
|
||||
properties[k] = prop
|
||||
}
|
||||
|
||||
return spec.Schema{
|
||||
@ -514,25 +601,28 @@ func (parser *Parser) parseTypeExpr(pkgName, typeName string, typeExpr ast.Expr,
|
||||
Type: []string{"object"},
|
||||
Properties: properties,
|
||||
Required: required,
|
||||
},
|
||||
}
|
||||
}}, nil
|
||||
|
||||
// type Foo Baz
|
||||
case *ast.Ident:
|
||||
refTypeName := fullTypeName(pkgName, expr.Name)
|
||||
if _, isParsed := parser.swagger.Definitions[refTypeName]; !isParsed {
|
||||
typedef := parser.TypeDefinitions[pkgName][expr.Name]
|
||||
parser.ParseDefinition(pkgName, expr.Name, typedef)
|
||||
if typedef, ok := parser.TypeDefinitions[pkgName][expr.Name]; ok {
|
||||
parser.ParseDefinition(pkgName, expr.Name, typedef)
|
||||
}
|
||||
}
|
||||
return parser.swagger.Definitions[refTypeName]
|
||||
return parser.swagger.Definitions[refTypeName], nil
|
||||
|
||||
// type Foo *Baz
|
||||
case *ast.StarExpr:
|
||||
return parser.parseTypeExpr(pkgName, typeName, expr.X, true)
|
||||
return parser.parseTypeExpr(pkgName, typeName, expr.X)
|
||||
|
||||
// type Foo []Baz
|
||||
case *ast.ArrayType:
|
||||
itemSchema := parser.parseTypeExpr(pkgName, "", expr.Elt, true)
|
||||
itemSchema, err := parser.parseTypeExpr(pkgName, "", expr.Elt)
|
||||
if err != nil {
|
||||
return spec.Schema{}, err
|
||||
}
|
||||
return spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
@ -540,7 +630,7 @@ func (parser *Parser) parseTypeExpr(pkgName, typeName string, typeExpr ast.Expr,
|
||||
Schema: &itemSchema,
|
||||
},
|
||||
},
|
||||
}
|
||||
}, nil
|
||||
|
||||
// type Foo pkg.Bar
|
||||
case *ast.SelectorExpr:
|
||||
@ -552,20 +642,33 @@ func (parser *Parser) parseTypeExpr(pkgName, typeName string, typeExpr ast.Expr,
|
||||
typedef := parser.TypeDefinitions[pkgName][typeName]
|
||||
parser.ParseDefinition(pkgName, typeName, typedef)
|
||||
}
|
||||
return parser.swagger.Definitions[refTypeName]
|
||||
return parser.swagger.Definitions[refTypeName], nil
|
||||
}
|
||||
|
||||
// type Foo map[string]Bar
|
||||
case *ast.MapType:
|
||||
itemSchema, err := parser.parseTypeExpr(pkgName, "", expr.Value)
|
||||
if err != nil {
|
||||
return spec.Schema{}, err
|
||||
}
|
||||
return spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
AdditionalProperties: &spec.SchemaOrBool{
|
||||
Schema: &itemSchema,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
// ...
|
||||
default:
|
||||
log.Printf("Type definition of type '%T' is not supported yet. Using 'object' instead.\n", typeExpr)
|
||||
Printf("Type definition of type '%T' is not supported yet. Using 'object' instead.\n", typeExpr)
|
||||
}
|
||||
|
||||
return spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
},
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
type structField struct {
|
||||
@ -582,18 +685,25 @@ type structField struct {
|
||||
minLength *int64
|
||||
enums []interface{}
|
||||
defaultValue interface{}
|
||||
extensions map[string]interface{}
|
||||
}
|
||||
|
||||
func (parser *Parser) parseStruct(pkgName string, field *ast.Field) (properties map[string]spec.Schema) {
|
||||
properties = map[string]spec.Schema{}
|
||||
structField := parser.parseField(field)
|
||||
func (parser *Parser) parseStruct(pkgName string, field *ast.Field) (map[string]spec.Schema, error) {
|
||||
properties := map[string]spec.Schema{}
|
||||
structField, err := parser.parseField(field)
|
||||
if err != nil {
|
||||
return properties, nil
|
||||
}
|
||||
if structField.name == "" {
|
||||
return
|
||||
return properties, nil
|
||||
}
|
||||
var desc string
|
||||
if field.Doc != nil {
|
||||
desc = strings.TrimSpace(field.Doc.Text())
|
||||
}
|
||||
if desc == "" && field.Comment != nil {
|
||||
desc = strings.TrimSpace(field.Comment.Text())
|
||||
}
|
||||
// TODO: find package of schemaType and/or arrayType
|
||||
|
||||
if structField.crossPkg != "" {
|
||||
@ -684,13 +794,20 @@ func (parser *Parser) parseStruct(pkgName string, field *ast.Field) (properties
|
||||
SwaggerSchemaProps: spec.SwaggerSchemaProps{
|
||||
Example: structField.exampleValue,
|
||||
},
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: structField.extensions,
|
||||
},
|
||||
}
|
||||
|
||||
nestStruct, ok := field.Type.(*ast.StructType)
|
||||
if ok {
|
||||
props := map[string]spec.Schema{}
|
||||
nestRequired := make([]string, 0)
|
||||
for _, v := range nestStruct.Fields.List {
|
||||
p := parser.parseStruct(pkgName, v)
|
||||
p, err := parser.parseStruct(pkgName, v)
|
||||
if err != nil {
|
||||
return properties, err
|
||||
}
|
||||
for k, v := range p {
|
||||
if v.SchemaProps.Type[0] != "object" {
|
||||
nestRequired = append(nestRequired, v.SchemaProps.Required...)
|
||||
@ -720,10 +837,10 @@ func (parser *Parser) parseStruct(pkgName string, field *ast.Field) (properties
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
return properties, nil
|
||||
}
|
||||
|
||||
func (parser *Parser) parseAnonymousField(pkgName string, field *ast.Field) map[string]spec.Schema {
|
||||
func (parser *Parser) parseAnonymousField(pkgName string, field *ast.Field) (map[string]spec.Schema, []string, error) {
|
||||
properties := make(map[string]spec.Schema)
|
||||
|
||||
fullTypeName := ""
|
||||
@ -733,10 +850,17 @@ func (parser *Parser) parseAnonymousField(pkgName string, field *ast.Field) map[
|
||||
case *ast.StarExpr:
|
||||
if ftypeX, ok := ftype.X.(*ast.Ident); ok {
|
||||
fullTypeName = ftypeX.Name
|
||||
} else if ftypeX, ok := ftype.X.(*ast.SelectorExpr); ok {
|
||||
if packageX, ok := ftypeX.X.(*ast.Ident); ok {
|
||||
fullTypeName = fmt.Sprintf("%s.%s", packageX.Name, ftypeX.Sel.Name)
|
||||
}
|
||||
} else {
|
||||
Printf("Composite field type of '%T' is unhandle by parser. Skipping", ftype)
|
||||
return properties, []string{}, nil
|
||||
}
|
||||
default:
|
||||
log.Printf("Field type of '%T' is unsupported. Skipping", ftype)
|
||||
return properties
|
||||
Printf("Field type of '%T' is unsupported. Skipping", ftype)
|
||||
return properties, []string{}, nil
|
||||
}
|
||||
|
||||
typeName := fullTypeName
|
||||
@ -746,8 +870,10 @@ func (parser *Parser) parseAnonymousField(pkgName string, field *ast.Field) map[
|
||||
}
|
||||
|
||||
typeSpec := parser.TypeDefinitions[pkgName][typeName]
|
||||
schema := parser.parseTypeExpr(pkgName, typeName, typeSpec.Type, false)
|
||||
|
||||
schema, err := parser.parseTypeExpr(pkgName, typeName, typeSpec.Type)
|
||||
if err != nil {
|
||||
return properties, []string{}, err
|
||||
}
|
||||
schemaType := "unknown"
|
||||
if len(schema.SchemaProps.Type) > 0 {
|
||||
schemaType = schema.SchemaProps.Type[0]
|
||||
@ -761,14 +887,14 @@ func (parser *Parser) parseAnonymousField(pkgName string, field *ast.Field) map[
|
||||
case "array":
|
||||
properties[typeName] = schema
|
||||
default:
|
||||
log.Printf("Can't extract properties from a schema of type '%s'", schemaType)
|
||||
Printf("Can't extract properties from a schema of type '%s'", schemaType)
|
||||
}
|
||||
|
||||
return properties
|
||||
return properties, schema.SchemaProps.Required, nil
|
||||
}
|
||||
|
||||
func (parser *Parser) parseField(field *ast.Field) *structField {
|
||||
prop := getPropertyName(field, parser)
|
||||
func (parser *Parser) parseField(field *ast.Field) (*structField, error) {
|
||||
prop := getPropertyName(field.Type, parser)
|
||||
if len(prop.ArrayType) == 0 {
|
||||
CheckSchemaType(prop.SchemaType)
|
||||
} else {
|
||||
@ -793,7 +919,7 @@ func (parser *Parser) parseField(field *ast.Field) *structField {
|
||||
}
|
||||
|
||||
if field.Tag == nil {
|
||||
return structField
|
||||
return structField, nil
|
||||
}
|
||||
// `json:"tag"` -> json:"tag"
|
||||
structTag := reflect.StructTag(strings.Replace(field.Tag.Value, "`", "", -1))
|
||||
@ -818,8 +944,13 @@ func (parser *Parser) parseField(field *ast.Field) *structField {
|
||||
if 0 < len(parts) && len(parts) <= 2 {
|
||||
newSchemaType := parts[0]
|
||||
newArrayType := structField.arrayType
|
||||
if len(parts) >= 2 && newSchemaType == "array" {
|
||||
newArrayType = parts[1]
|
||||
if len(parts) >= 2 {
|
||||
if newSchemaType == "array" {
|
||||
newArrayType = parts[1]
|
||||
} else if newSchemaType == "primitive" {
|
||||
newSchemaType = parts[1]
|
||||
newArrayType = parts[1]
|
||||
}
|
||||
}
|
||||
|
||||
CheckSchemaType(newSchemaType)
|
||||
@ -829,7 +960,11 @@ func (parser *Parser) parseField(field *ast.Field) *structField {
|
||||
}
|
||||
}
|
||||
if exampleTag := structTag.Get("example"); exampleTag != "" {
|
||||
structField.exampleValue = defineTypeOfExample(structField.schemaType, structField.arrayType, exampleTag)
|
||||
example, err := defineTypeOfExample(structField.schemaType, structField.arrayType, exampleTag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
structField.exampleValue = example
|
||||
}
|
||||
if formatTag := structTag.Get("format"); formatTag != "" {
|
||||
structField.formatType = formatTag
|
||||
@ -850,6 +985,17 @@ func (parser *Parser) parseField(field *ast.Field) *structField {
|
||||
}
|
||||
}
|
||||
}
|
||||
if extensionsTag := structTag.Get("extensions"); extensionsTag != "" {
|
||||
structField.extensions = map[string]interface{}{}
|
||||
for _, val := range strings.Split(extensionsTag, ",") {
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
if len(parts) == 2 {
|
||||
structField.extensions[parts[0]] = parts[1]
|
||||
} else {
|
||||
structField.extensions[parts[0]] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if enumsTag := structTag.Get("enums"); enumsTag != "" {
|
||||
enumType := structField.schemaType
|
||||
if structField.schemaType == "array" {
|
||||
@ -865,15 +1011,33 @@ func (parser *Parser) parseField(field *ast.Field) *structField {
|
||||
}
|
||||
|
||||
if IsNumericType(structField.schemaType) || IsNumericType(structField.arrayType) {
|
||||
structField.maximum = getFloatTag(structTag, "maximum")
|
||||
structField.minimum = getFloatTag(structTag, "minimum")
|
||||
maximum, err := getFloatTag(structTag, "maximum")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
structField.maximum = maximum
|
||||
|
||||
minimum, err := getFloatTag(structTag, "minimum")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
structField.minimum = minimum
|
||||
}
|
||||
if structField.schemaType == "string" || structField.arrayType == "string" {
|
||||
structField.maxLength = getIntTag(structTag, "maxLength")
|
||||
structField.minLength = getIntTag(structTag, "minLength")
|
||||
maxLength, err := getIntTag(structTag, "maxLength")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
structField.maxLength = maxLength
|
||||
|
||||
minLength, err := getIntTag(structTag, "minLength")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
structField.minLength = minLength
|
||||
}
|
||||
|
||||
return structField
|
||||
return structField, nil
|
||||
}
|
||||
|
||||
func replaceLastTag(slice []spec.Tag, element spec.Tag) {
|
||||
@ -881,32 +1045,32 @@ func replaceLastTag(slice []spec.Tag, element spec.Tag) {
|
||||
slice = append(slice, element)
|
||||
}
|
||||
|
||||
func getFloatTag(structTag reflect.StructTag, tagName string) *float64 {
|
||||
func getFloatTag(structTag reflect.StructTag, tagName string) (*float64, error) {
|
||||
strValue := structTag.Get(tagName)
|
||||
if strValue == "" {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
value, err := strconv.ParseFloat(strValue, 64)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("can't parse numeric value of %q tag: %v", tagName, err))
|
||||
return nil, fmt.Errorf("can't parse numeric value of %q tag: %v", tagName, err)
|
||||
}
|
||||
|
||||
return &value
|
||||
return &value, nil
|
||||
}
|
||||
|
||||
func getIntTag(structTag reflect.StructTag, tagName string) *int64 {
|
||||
func getIntTag(structTag reflect.StructTag, tagName string) (*int64, error) {
|
||||
strValue := structTag.Get(tagName)
|
||||
if strValue == "" {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
value, err := strconv.ParseInt(strValue, 10, 64)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("can't parse numeric value of %q tag: %v", tagName, err))
|
||||
return nil, fmt.Errorf("can't parse numeric value of %q tag: %v", tagName, err)
|
||||
}
|
||||
|
||||
return &value
|
||||
return &value, nil
|
||||
}
|
||||
|
||||
func toSnakeCase(in string) string {
|
||||
@ -942,37 +1106,41 @@ func toLowerCamelCase(in string) string {
|
||||
}
|
||||
|
||||
// defineTypeOfExample example value define the type (object and array unsupported)
|
||||
func defineTypeOfExample(schemaType, arrayType, exampleValue string) interface{} {
|
||||
func defineTypeOfExample(schemaType, arrayType, exampleValue string) (interface{}, error) {
|
||||
switch schemaType {
|
||||
case "string":
|
||||
return exampleValue
|
||||
return exampleValue, nil
|
||||
case "number":
|
||||
v, err := strconv.ParseFloat(exampleValue, 64)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("example value %s can't convert to %s err: %s", exampleValue, schemaType, err))
|
||||
return nil, fmt.Errorf("example value %s can't convert to %s err: %s", exampleValue, schemaType, err)
|
||||
}
|
||||
return v
|
||||
return v, nil
|
||||
case "integer":
|
||||
v, err := strconv.Atoi(exampleValue)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("example value %s can't convert to %s err: %s", exampleValue, schemaType, err))
|
||||
return nil, fmt.Errorf("example value %s can't convert to %s err: %s", exampleValue, schemaType, err)
|
||||
}
|
||||
return v
|
||||
return v, nil
|
||||
case "boolean":
|
||||
v, err := strconv.ParseBool(exampleValue)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("example value %s can't convert to %s err: %s", exampleValue, schemaType, err))
|
||||
return nil, fmt.Errorf("example value %s can't convert to %s err: %s", exampleValue, schemaType, err)
|
||||
}
|
||||
return v
|
||||
return v, nil
|
||||
case "array":
|
||||
values := strings.Split(exampleValue, ",")
|
||||
result := make([]interface{}, 0)
|
||||
for _, value := range values {
|
||||
result = append(result, defineTypeOfExample(arrayType, "", value))
|
||||
v, err := defineTypeOfExample(arrayType, "", value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, v)
|
||||
}
|
||||
return result
|
||||
return result, nil
|
||||
default:
|
||||
panic(fmt.Errorf("%s is unsupported type in example value", schemaType))
|
||||
return nil, fmt.Errorf("%s is unsupported type in example value", schemaType)
|
||||
}
|
||||
}
|
||||
|
||||
@ -982,7 +1150,7 @@ func (parser *Parser) getAllGoFileInfo(searchDir string) error {
|
||||
}
|
||||
|
||||
func (parser *Parser) visit(path string, f os.FileInfo, err error) error {
|
||||
if err := Skip(f); err != nil {
|
||||
if err := parser.Skip(path, f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -990,7 +1158,7 @@ func (parser *Parser) visit(path string, f os.FileInfo, err error) error {
|
||||
fset := token.NewFileSet() // positions are relative to fset
|
||||
astFile, err := goparser.ParseFile(fset, path, nil, goparser.ParseComments)
|
||||
if err != nil {
|
||||
log.Panicf("ParseFile panic:%+v", err)
|
||||
return fmt.Errorf("ParseFile error:%+v", err)
|
||||
}
|
||||
|
||||
parser.files[path] = astFile
|
||||
@ -999,10 +1167,12 @@ func (parser *Parser) visit(path string, f os.FileInfo, err error) error {
|
||||
}
|
||||
|
||||
// Skip returns filepath.SkipDir error if match vendor and hidden folder
|
||||
func Skip(f os.FileInfo) error {
|
||||
// exclude vendor folder
|
||||
if f.IsDir() && f.Name() == "vendor" {
|
||||
return filepath.SkipDir
|
||||
func (parser *Parser) Skip(path string, f os.FileInfo) error {
|
||||
|
||||
if !parser.ParseVendor { // ignore vendor
|
||||
if f.IsDir() && f.Name() == "vendor" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
}
|
||||
|
||||
// exclude all hidden folder
|
||||
|
93
vendor/github.com/swaggo/swag/property.go
generated
vendored
93
vendor/github.com/swaggo/swag/property.go
generated
vendored
@ -4,7 +4,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -61,83 +60,69 @@ func parseFieldSelectorExpr(astTypeSelectorExpr *ast.SelectorExpr, parser *Parse
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("%s is not supported. but it will be set with string temporary. Please report any problems.\n", astTypeSelectorExpr.Sel.Name)
|
||||
Printf("%s is not supported. but it will be set with string temporary. Please report any problems.\n", astTypeSelectorExpr.Sel.Name)
|
||||
return propertyName{SchemaType: "string", ArrayType: "string"}
|
||||
}
|
||||
|
||||
// getPropertyName returns the string value for the given field if it exists, otherwise it panics.
|
||||
// allowedValues: array, boolean, integer, null, number, object, string
|
||||
func getPropertyName(field *ast.Field, parser *Parser) propertyName {
|
||||
if astTypeSelectorExpr, ok := field.Type.(*ast.SelectorExpr); ok {
|
||||
func getPropertyName(expr ast.Expr, parser *Parser) propertyName {
|
||||
if astTypeSelectorExpr, ok := expr.(*ast.SelectorExpr); ok {
|
||||
return parseFieldSelectorExpr(astTypeSelectorExpr, parser, newProperty)
|
||||
}
|
||||
|
||||
// check if it is a custom type
|
||||
typeName := fmt.Sprintf("%v", field.Type)
|
||||
typeName := fmt.Sprintf("%v", expr)
|
||||
if actualPrimitiveType, isCustomType := parser.CustomPrimitiveTypes[typeName]; isCustomType {
|
||||
return propertyName{SchemaType: actualPrimitiveType, ArrayType: actualPrimitiveType}
|
||||
}
|
||||
|
||||
if astTypeIdent, ok := field.Type.(*ast.Ident); ok {
|
||||
if astTypeIdent, ok := expr.(*ast.Ident); ok {
|
||||
name := astTypeIdent.Name
|
||||
schemeType := TransToValidSchemeType(name)
|
||||
return propertyName{SchemaType: schemeType, ArrayType: schemeType}
|
||||
}
|
||||
if ptr, ok := field.Type.(*ast.StarExpr); ok {
|
||||
if astTypeSelectorExpr, ok := ptr.X.(*ast.SelectorExpr); ok {
|
||||
return parseFieldSelectorExpr(astTypeSelectorExpr, parser, newProperty)
|
||||
}
|
||||
// TODO support custom pointer type?
|
||||
if _, ok := ptr.X.(*ast.MapType); ok { // if map
|
||||
//TODO support map
|
||||
return propertyName{SchemaType: "object", ArrayType: "object"}
|
||||
}
|
||||
if _, ok := ptr.X.(*ast.StructType); ok { // if struct
|
||||
return propertyName{SchemaType: "object", ArrayType: "object"}
|
||||
}
|
||||
if astTypeIdent, ok := ptr.X.(*ast.Ident); ok {
|
||||
name := astTypeIdent.Name
|
||||
schemeType := TransToValidSchemeType(name)
|
||||
return propertyName{SchemaType: schemeType, ArrayType: schemeType}
|
||||
}
|
||||
if astTypeArray, ok := ptr.X.(*ast.ArrayType); ok { // if array
|
||||
if astTypeArrayExpr, ok := astTypeArray.Elt.(*ast.SelectorExpr); ok {
|
||||
return parseFieldSelectorExpr(astTypeArrayExpr, parser, newArrayProperty)
|
||||
}
|
||||
if astTypeArrayIdent, ok := astTypeArray.Elt.(*ast.Ident); ok {
|
||||
name := TransToValidSchemeType(astTypeArrayIdent.Name)
|
||||
return propertyName{SchemaType: "array", ArrayType: name}
|
||||
}
|
||||
}
|
||||
|
||||
if ptr, ok := expr.(*ast.StarExpr); ok {
|
||||
return getPropertyName(ptr.X, parser)
|
||||
}
|
||||
if astTypeArray, ok := field.Type.(*ast.ArrayType); ok { // if array
|
||||
if astTypeArrayExpr, ok := astTypeArray.Elt.(*ast.SelectorExpr); ok {
|
||||
return parseFieldSelectorExpr(astTypeArrayExpr, parser, newArrayProperty)
|
||||
}
|
||||
if astTypeArrayExpr, ok := astTypeArray.Elt.(*ast.StarExpr); ok {
|
||||
if astTypeArraySel, ok := astTypeArrayExpr.X.(*ast.SelectorExpr); ok {
|
||||
return parseFieldSelectorExpr(astTypeArraySel, parser, newArrayProperty)
|
||||
}
|
||||
if astTypeArrayIdent, ok := astTypeArrayExpr.X.(*ast.Ident); ok {
|
||||
name := TransToValidSchemeType(astTypeArrayIdent.Name)
|
||||
return propertyName{SchemaType: "array", ArrayType: name}
|
||||
}
|
||||
}
|
||||
itemTypeName := TransToValidSchemeType(fmt.Sprintf("%s", astTypeArray.Elt))
|
||||
if actualPrimitiveType, isCustomType := parser.CustomPrimitiveTypes[itemTypeName]; isCustomType {
|
||||
itemTypeName = actualPrimitiveType
|
||||
}
|
||||
return propertyName{SchemaType: "array", ArrayType: itemTypeName}
|
||||
|
||||
if astTypeArray, ok := expr.(*ast.ArrayType); ok { // if array
|
||||
return getArrayPropertyName(astTypeArray, parser)
|
||||
}
|
||||
if _, ok := field.Type.(*ast.MapType); ok { // if map
|
||||
|
||||
if _, ok := expr.(*ast.MapType); ok { // if map
|
||||
//TODO: support map
|
||||
return propertyName{SchemaType: "object", ArrayType: "object"}
|
||||
}
|
||||
if _, ok := field.Type.(*ast.StructType); ok { // if struct
|
||||
|
||||
if _, ok := expr.(*ast.StructType); ok { // if struct
|
||||
return propertyName{SchemaType: "object", ArrayType: "object"}
|
||||
}
|
||||
if _, ok := field.Type.(*ast.InterfaceType); ok { // if interface{}
|
||||
|
||||
if _, ok := expr.(*ast.InterfaceType); ok { // if interface{}
|
||||
return propertyName{SchemaType: "object", ArrayType: "object"}
|
||||
}
|
||||
panic("not supported" + fmt.Sprint(field.Type))
|
||||
|
||||
panic("not supported" + fmt.Sprint(expr))
|
||||
}
|
||||
|
||||
func getArrayPropertyName(astTypeArray *ast.ArrayType, parser *Parser) propertyName {
|
||||
if astTypeArrayExpr, ok := astTypeArray.Elt.(*ast.SelectorExpr); ok {
|
||||
return parseFieldSelectorExpr(astTypeArrayExpr, parser, newArrayProperty)
|
||||
}
|
||||
if astTypeArrayExpr, ok := astTypeArray.Elt.(*ast.StarExpr); ok {
|
||||
if astTypeArraySel, ok := astTypeArrayExpr.X.(*ast.SelectorExpr); ok {
|
||||
return parseFieldSelectorExpr(astTypeArraySel, parser, newArrayProperty)
|
||||
}
|
||||
if astTypeArrayIdent, ok := astTypeArrayExpr.X.(*ast.Ident); ok {
|
||||
name := TransToValidSchemeType(astTypeArrayIdent.Name)
|
||||
return propertyName{SchemaType: "array", ArrayType: name}
|
||||
}
|
||||
}
|
||||
itemTypeName := TransToValidSchemeType(fmt.Sprintf("%s", astTypeArray.Elt))
|
||||
if actualPrimitiveType, isCustomType := parser.CustomPrimitiveTypes[itemTypeName]; isCustomType {
|
||||
itemTypeName = actualPrimitiveType
|
||||
}
|
||||
return propertyName{SchemaType: "array", ArrayType: itemTypeName}
|
||||
}
|
||||
|
2
vendor/github.com/swaggo/swag/schema.go
generated
vendored
2
vendor/github.com/swaggo/swag/schema.go
generated
vendored
@ -2,7 +2,7 @@ package swag
|
||||
|
||||
import "fmt"
|
||||
|
||||
// CheckSchemaType TODO: NEEDS COMMENT INFO
|
||||
// CheckSchemaType begins panicking if typeName is not a name of primitive type
|
||||
func CheckSchemaType(typeName string) {
|
||||
if !IsPrimitiveType(typeName) {
|
||||
panic(fmt.Errorf("%s is not basic types", typeName))
|
||||
|
2
vendor/github.com/swaggo/swag/version.go
generated
vendored
2
vendor/github.com/swaggo/swag/version.go
generated
vendored
@ -1,4 +1,4 @@
|
||||
package swag
|
||||
|
||||
// Version of swag
|
||||
const Version = "v1.4.0"
|
||||
const Version = "v1.5.0"
|
||||
|
Reference in New Issue
Block a user