[
  {
    "path": ".github/ISSUE_TEMPLATE/Bug_report.md",
    "content": "---\r\nname: Bug report\r\nabout: Create a report to help us improve\r\n\r\n---\r\n\r\n**Describe the bug**\r\nA clear and concise description of what the bug is.\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n1. Go to '...'\r\n2. Click on '....'\r\n3. Scroll down to '....'\r\n4. See error\r\n\r\n**Expected behavior**\r\nA clear and concise description of what you expected to happen.\r\n\r\n**Screenshots**\r\nIf applicable, add screenshots to help explain your problem.\r\n\r\n**Your swag version**\r\ne.g. 1.4.1\r\n\r\n**Your go version**\r\ne.g. 1.12.0\r\n\r\n**Desktop (please complete the following information):**\r\n - OS: [e.g. iOS]\r\n - Browser: [e.g. chrome, safari]\r\n - Version: [e.g. 22]\r\n\r\n**Additional context**\r\nAdd any other context about the problem here.\r\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Feature_request.md",
    "content": "---\r\nname: Feature request\r\nabout: Suggest an idea for this project\r\n\r\n---\r\n\r\n**Is your feature request related to a problem? Please describe.**\r\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\r\n\r\n**Describe the solution you'd like**\r\nA clear and concise description of what you want to happen.\r\n\r\n**Describe alternatives you've considered**\r\nA clear and concise description of any alternative solutions or features you've considered.\r\n\r\n**Additional context**\r\nAdd any other context or screenshots about the feature request here.\r\n"
  },
  {
    "path": ".github/actions/danger/Dockerfile",
    "content": "FROM ruby:2.6\n\nLABEL \"com.github.actions.name\"=\"Danger\"\nLABEL \"com.github.actions.description\"=\"Run Danger\"\nLABEL \"com.github.actions.icon\"=\"alert-triangle\"\nLABEL \"com.github.actions.color\"=\"yellow\"\n\nRUN apt-get update -qq && apt-get install -y build-essential p7zip unzip\n\nRUN gem install danger -v '>= 5.10.3'\nRUN gem install danger-checkstyle_format\n\nENTRYPOINT \"danger\"\nCMD \"--verbose\"\n"
  },
  {
    "path": ".github/main.workflow",
    "content": "workflow \"DangerPullRequest\" {\n  on = \"pull_request\"\n  resolves = [\"Danger\"]\n}\n\naction \"Danger\" {\n  uses = \"pei0804/GithubActions/danger@master\"\n  secrets = [\"GITHUB_TOKEN\"]\n}\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: build\n\non:\n  push:\n    branches: [ master, v2 ]\n  pull_request:\n    branches: [ master, v2 ]\n\njobs:\n  test:\n    strategy:\n      matrix:\n        go: [ '1.21.x', '1.22.x', '1.23.x', '1.24.x', '1.25.x' ]\n        platform: [ubuntu-latest, macos-latest]\n    runs-on: ${{ matrix.platform }}\n    steps:\n      - uses: actions/checkout@v3\n      - name: Set up Go\n        uses: actions/setup-go@v3\n        with:\n          go-version: ${{ matrix.go }}\n      - name: deps\n        run:  make deps\n      - name: static program analysis\n        run: make fmt-check vet\n      - name: build\n        run: make build\n      - name: test\n        run: make test\n      - name: coverage\n        run: bash <(curl -s https://codecov.io/bash)\n"
  },
  {
    "path": ".github/workflows/docker.yml",
    "content": "name: docker\n\non:\n  push:\n    tags:\n      - 'v*'\n\npermissions:\n  contents: read\n  packages: write\n\njobs:\n  docker-build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Set up Docker Buildx\n        id: buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Login to Github Packages\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Docker meta\n        id: meta\n        uses: docker/metadata-action@v5\n        with:\n          images: ghcr.io/swaggo/swag\n\n      - name: Build image and push to GitHub Container Registry\n        id: docker_build\n        uses: docker/build-push-action@v5\n        with:\n          context: .\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            ghcr.io/${{ github.repository }}:latest\n            ghcr.io/${{ github.repository }}:${{github.ref_name}}\n          labels: ${{ steps.meta.outputs.labels }}\n\n      - name: Image digest\n        run: echo ${{ steps.docker_build.outputs.digest }}\n"
  },
  {
    "path": ".gitignore",
    "content": "dist\ntestdata/simple*/docs\ntestdata/quotes/docs\ntestdata/quotes/quotes.so\ntestdata/delims/docs\ntestdata/delims/delims.so\nexample/basic/docs/*\nexample/celler/docs/*\ncover.out\n\n\n# Test binary, build with `go test -c`\n*.test\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\n.idea\n.vscode\n\n# Etc\n.DS_Store\n\n/swag\n/swag.exe\n"
  },
  {
    "path": ".goreleaser.yml",
    "content": "build:\n  main: cmd/swag/main.go\n  goos:\n    - linux\n    - darwin\n  goarch:\n    - amd64\n    - arm64\n    - 386\n  env:\n    - CGO_ENABLED=0\n\narchives:\n  - id: foo\n    name_template: >-\n      {{ .ProjectName }}_\n      {{- .Version }}_\n      {{- if eq .Os \"linux\"}}Linux{{ else if eq .Os \"darwin\"}}Darwin{{ else }}{{ .Os }}{{ end }}_\n      {{- if eq .Arch \"386\" }}i386{{ else if eq .Arch \"amd64\" }}x86_64{{ else }}{{ .Arch }}{{ end }}\n\nchecksum:\n  name_template: 'checksums.txt'\nsnapshot:\n  name_template: \"{{ .Tag }}-next\"\nchangelog:\n  sort: asc\n  filters:\n    exclude:\n    - '^docs:'\n    - '^test:'\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [gitter.im/swaggo/swag](https://gitter.im/swaggo/swag).The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nWhen contributing to this repository, please first discuss the change you wish to make via issue,\nemail, or any other method with the owners of this repository before making a change. \n\nPlease note we have a code of conduct, please follow it in all your interactions with the project.\n\n## Pull Request Process\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n\nPlease make an issue first if the change is likely to increase.\n"
  },
  {
    "path": "Dockerfile",
    "content": "# Dockerfile References: https://docs.docker.com/engine/reference/builder/\n\n# Start from the latest golang base image\nFROM --platform=$BUILDPLATFORM golang:1.24-alpine as builder\n\n# Set the Current Working Directory inside the container\nWORKDIR /app\n\n# Copy go mod and sum files\nCOPY go.mod go.sum ./\n\n# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed\nRUN go mod download\n\n# Copy the source from the current directory to the Working Directory inside the container\nCOPY . .\n\n# Configure go compiler target platform\nARG TARGETOS\nARG TARGETARCH\nENV GOARCH=$TARGETARCH \\\n    GOOS=$TARGETOS\n\n# Build the Go app\nRUN CGO_ENABLED=0 GOOS=linux go build -v -a -installsuffix cgo -o swag cmd/swag/main.go\n\n\n######## Start a new stage from scratch #######\nFROM --platform=$TARGETPLATFORM scratch\n\nWORKDIR /code/\n\n# Copy the Pre-built binary file from the previous stage\nCOPY --from=builder /app/swag /bin/swag\n\nENTRYPOINT [\"/bin/swag\"]\n"
  },
  {
    "path": "Makefile",
    "content": "GOCMD:=$(shell which go)\nGOLINT:=$(shell which golint)\nGOIMPORT:=$(shell which goimports)\nGOFMT:=$(shell which gofmt)\nGOBUILD:=$(GOCMD) build\nGOINSTALL:=$(GOCMD) install\nGOCLEAN:=$(GOCMD) clean\nGOTEST:=$(GOCMD) test\nGOMODTIDY:=$(GOCMD) mod tidy\nGOGET:=$(GOCMD) get\nGOLIST:=$(GOCMD) list\nGOVET:=$(GOCMD) vet\nGOPATH:=$(shell $(GOCMD) env GOPATH)\nu := $(if $(update),-u)\n\nBINARY_NAME:=swag\nPACKAGES:=$(shell $(GOLIST) github.com/swaggo/swag github.com/swaggo/swag/cmd/swag github.com/swaggo/swag/gen github.com/swaggo/swag/format)\nGOFILES:=$(shell find . -name \"*.go\" -type f)\n\nall: test build\n\n.PHONY: build\nbuild: deps\n\t$(GOBUILD) -o $(BINARY_NAME) ./cmd/swag\n\n.PHONY: install\ninstall: deps\n\t$(GOINSTALL) ./cmd/swag\n\n.PHONY: test\ntest:\n\techo \"mode: count\" > coverage.out\n\tfor PKG in $(PACKAGES); do \\\n\t\t$(GOCMD) test -v -covermode=count -coverprofile=profile.out $$PKG > tmp.out; \\\n\t\tcat tmp.out; \\\n\t\tif grep -q \"^--- FAIL\" tmp.out; then \\\n\t\t\trm tmp.out; \\\n\t\t\texit 1; \\\n\t\telif grep -q \"build failed\" tmp.out; then \\\n\t\t\trm tmp.out; \\\n\t\t\texit; \\\n\t\tfi; \\\n\t\tif [ -f profile.out ]; then \\\n\t\t\tcat profile.out | grep -v \"mode:\" >> coverage.out; \\\n\t\t\trm profile.out; \\\n\t\tfi; \\\n\tdone\n\n.PHONY: clean\nclean:\n\t$(GOCLEAN)\n\trm -f $(BINARY_NAME)\n\n.PHONY: deps\ndeps:\n\t$(GOMODTIDY)\n\n.PHONY: vet\nvet: deps\n\t$(GOVET) $(PACKAGES)\n\n.PHONY: fmt\nfmt:\n\t$(GOFMT) -s -w $(GOFILES)\n\n.PHONY: fmt-check\nfmt-check:\n\t@diff=$$($(GOFMT) -s -d $(GOFILES)); \\\n\tif [ -n \"$$diff\" ]; then \\\n\t\techo \"Please run 'make fmt' and commit the result:\"; \\\n\t\techo \"$${diff}\"; \\\n\t\texit 1; \\\n\tfi;\n\n.PHONY: view-covered\nview-covered:\n\t$(GOTEST) -coverprofile=cover.out $(TARGET)\n\t$(GOCMD) tool cover -html=cover.out\n"
  },
  {
    "path": "PULL_REQUEST_TEMPLATE.md",
    "content": "**Describe the PR**\ne.g. add cool parser.\n\n**Relation issue**\ne.g. https://github.com/swaggo/swag/pull/118/files\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": "README.md",
    "content": "# swag\n\n🌍 *[English](README.md) ∙ [简体中文](README_zh-CN.md) ∙ [Português](README_pt.md)*\n\n<img align=\"right\" width=\"180px\" src=\"https://raw.githubusercontent.com/swaggo/swag/master/assets/swaggo.png\">\n\n[![Build Status](https://github.com/swaggo/swag/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/features/actions)\n[![Coverage Status](https://img.shields.io/codecov/c/github/swaggo/swag/master.svg)](https://codecov.io/gh/swaggo/swag)\n[![Go Report Card](https://goreportcard.com/badge/github.com/swaggo/swag)](https://goreportcard.com/report/github.com/swaggo/swag)\n[![Go Doc](https://godoc.org/github.com/swaggo/swagg?status.svg)](https://godoc.org/github.com/swaggo/swag)\n[![Backers on Open Collective](https://opencollective.com/swag/backers/badge.svg)](#backers)\n[![Sponsors on Open Collective](https://opencollective.com/swag/sponsors/badge.svg)](#sponsors) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fswaggo%2Fswag.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fswaggo%2Fswag?ref=badge_shield)\n[![Release](https://img.shields.io/github/release/swaggo/swag.svg?style=flat-square)](https://github.com/swaggo/swag/releases)\n\n\nSwag 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).\n\n## Contents\n - [Getting started](#getting-started)\n - [Supported Web Frameworks](#supported-web-frameworks)\n - [How to use it with Gin](#how-to-use-it-with-gin)\n - [The swag formatter](#the-swag-formatter)\n - [Implementation Status](#implementation-status)\n - [Declarative Comments Format](#declarative-comments-format)\n\t- [General API Info](#general-api-info)\n\t- [API Operation](#api-operation)\n\t- [Security](#security)\n - [Examples](#examples)\n\t- [Descriptions over multiple lines](#descriptions-over-multiple-lines)\n\t- [User defined structure with an array type](#user-defined-structure-with-an-array-type)\n\t- [Function scoped struct declaration](#function-scoped-struct-declaration)\n\t- [Model composition in response](#model-composition-in-response)\n        - [Add request headers](#add-request-headers)\n\t- [Add response headers](#add-response-headers)\n\t- [Use multiple path params](#use-multiple-path-params)\n\t- [Example value of struct](#example-value-of-struct)\n\t- [SchemaExample of body](#schemaexample-of-body)\n\t- [Description of struct](#description-of-struct)\n\t- [Use swaggertype tag to supported custom type](#use-swaggertype-tag-to-supported-custom-type)\n\t- [Use global overrides to support a custom type](#use-global-overrides-to-support-a-custom-type)\n\t- [Use swaggerignore tag to exclude a field](#use-swaggerignore-tag-to-exclude-a-field)\n\t- [Add extension info to struct field](#add-extension-info-to-struct-field)\n\t- [Rename model to display](#rename-model-to-display)\n\t- [How to use security annotations](#how-to-use-security-annotations)\n\t- [Add a description for enum items](#add-a-description-for-enum-items)\n\t- [Generate only specific docs file types](#generate-only-specific-docs-file-types)\n    - [How to use Go generic types](#how-to-use-generics)\n- [About the Project](#about-the-project)\n\n## Getting started\n\n1. Add comments to your API source code, See [Declarative Comments Format](#declarative-comments-format).\n\n2. Install swag by using:\n```sh\ngo install github.com/swaggo/swag/cmd/swag@latest\n```\nTo build from source you need [Go](https://golang.org/dl/) (1.19 or newer).\n\nAlternatively you can run the docker image:\n```sh\ndocker run --rm -v $(pwd):/code ghcr.io/swaggo/swag:latest\n```\n\nOr download a pre-compiled binary from the [release page](https://github.com/swaggo/swag/releases).\n\n3. 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`).\n```sh\nswag init\n```\n\n  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.\n  ```go\n  import _ \"example-module-name/docs\"\n  ```\n  ```sh\n  swag init -g http/api.go\n  ```\n\n4. (optional) Use `swag fmt` format the SWAG comment. (Please upgrade to the latest version)\n\n  ```sh\n  swag fmt\n  ```\n\n## swag cli\n\n```sh\nswag init -h\nNAME:\n   swag init - Create docs.go\n\nUSAGE:\n   swag init [command options] [arguments...]\n\nOPTIONS:\n   --quiet, -q                            Make the logger quiet. (default: false)\n   --generalInfo value, -g value          Go file path in which 'swagger general API Info' is written (default: \"main.go\")\n   --dir value, -d value                  Directories you want to parse,comma separated and general-info file must be in the first one (default: \"./\")\n   --exclude value                        Exclude directories and files when searching, comma separated\n   --propertyStrategy value, -p value     Property Naming Strategy like snakecase,camelcase,pascalcase (default: \"camelcase\")\n   --output value, -o value               Output directory for all the generated files(swagger.json, swagger.yaml and docs.go) (default: \"./docs\")\n   --outputTypes value, --ot value        Output types of generated files (docs.go, swagger.json, swagger.yaml) like go,json,yaml (default: \"go,json,yaml\")\n   --parseVendor                          Parse go files in 'vendor' folder, disabled by default (default: false)\n   --parseDependency, --pd                Parse go files inside dependency folder, disabled by default (default: false)\n   --parseDependencyLevel, --pdl          Enhancement of '--parseDependency', parse go files inside dependency folder, 0 disabled, 1 only parse models, 2 only parse operations, 3 parse all (default: 0)\n   --markdownFiles value, --md value      Parse folder containing markdown files to use as description, disabled by default\n   --codeExampleFiles value, --cef value  Parse folder containing code example files to use for the x-codeSamples extension, disabled by default\n   --parseInternal                        Parse go files in internal packages, disabled by default (default: false)\n   --generatedTime                        Generate timestamp at the top of docs.go, disabled by default (default: false)\n   --parseDepth value                     Dependency parse depth (default: 100)\n   --requiredByDefault                    Set validation required for all fields by default (default: false)\n   --instanceName value                   This parameter can be used to name different swagger document instances. It is optional.\n   --overridesFile value                  File to read global type overrides from. (default: \".swaggo\")\n   --parseGoList                          Parse dependency via 'go list' (default: true)\n   --tags value, -t value                 A comma-separated list of tags to filter the APIs for which the documentation is generated.Special case if the tag is prefixed with the '!' character then the APIs with that tag will be excluded\n   --templateDelims value, --td value     Provide custom delimiters for Go template generation. The format is leftDelim,rightDelim. For example: \"[[,]]\"\n   --collectionFormat value, --cf value   Set default collection format (default: \"csv\")\n   --state value                          Initial state for the state machine (default: \"\"), @HostState in root file, @State in other files\n   --parseFuncBody                        Parse API info within body of functions in go files, disabled by default (default: false)\n   --help, -h                             show help (default: false)\n```\n\n```bash\nswag fmt -h\nNAME:\n   swag fmt - format swag comments\n\nUSAGE:\n   swag fmt [command options] [arguments...]\n\nOPTIONS:\n   --dir value, -d value          Directories you want to parse,comma separated and general-info file must be in the first one (default: \"./\")\n   --exclude value                Exclude directories and files when searching, comma separated\n   --generalInfo value, -g value  Go file path in which 'swagger general API Info' is written (default: \"main.go\")\n   --help, -h                     show help (default: false)\n\n```\n\n## Supported Web Frameworks\n\n- [gin](http://github.com/swaggo/gin-swagger)\n- [echo](http://github.com/swaggo/echo-swagger)\n- [buffalo](https://github.com/swaggo/buffalo-swagger)\n- [net/http](https://github.com/swaggo/http-swagger)\n- [gorilla/mux](https://github.com/swaggo/http-swagger)\n- [go-chi/chi](https://github.com/swaggo/http-swagger)\n- [flamingo](https://github.com/i-love-flamingo/swagger)\n- [fiber](https://github.com/gofiber/swagger)\n- [atreugo](https://github.com/Nerzal/atreugo-swagger)\n- [hertz](https://github.com/hertz-contrib/swagger)\n\n## How to use it with Gin\n\nFind the example source code [here](https://github.com/swaggo/swag/tree/master/example/celler).\n\nFinish the steps in [Getting started](#getting-started)\n1. After using `swag init` to generate Swagger 2.0 docs, import the following packages:\n```go\nimport \"github.com/swaggo/gin-swagger\" // gin-swagger middleware\nimport \"github.com/swaggo/files\" // swagger embed files\n```\n\n2. Add [General API](#general-api-info) annotations in `main.go` code:\n\n```go\n// @title           Swagger Example API\n// @version         1.0\n// @description     This is a sample server celler server.\n// @termsOfService  http://swagger.io/terms/\n\n// @contact.name   API Support\n// @contact.url    http://www.swagger.io/support\n// @contact.email  support@swagger.io\n\n// @license.name  Apache 2.0\n// @license.url   http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host      localhost:8080\n// @BasePath  /api/v1\n\n// @securityDefinitions.basic  BasicAuth\n\n// @externalDocs.description  OpenAPI\n// @externalDocs.url          https://swagger.io/resources/open-api/\nfunc main() {\n\tr := gin.Default()\n\n\tc := controller.NewController()\n\n\tv1 := r.Group(\"/api/v1\")\n\t{\n\t\taccounts := v1.Group(\"/accounts\")\n\t\t{\n\t\t\taccounts.GET(\":id\", c.ShowAccount)\n\t\t\taccounts.GET(\"\", c.ListAccounts)\n\t\t\taccounts.POST(\"\", c.AddAccount)\n\t\t\taccounts.DELETE(\":id\", c.DeleteAccount)\n\t\t\taccounts.PATCH(\":id\", c.UpdateAccount)\n\t\t\taccounts.POST(\":id/images\", c.UploadAccountImage)\n\t\t}\n    //...\n\t}\n\tr.GET(\"/swagger/*any\", ginSwagger.WrapHandler(swaggerFiles.Handler))\n\tr.Run(\":8080\")\n}\n//...\n```\n\nAdditionally some general API info can be set dynamically. The generated code package `docs` exports `SwaggerInfo` variable which we can use to set the title, description, version, host and base path programmatically. Example using Gin:\n\n```go\npackage main\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/swaggo/files\"\n\t\"github.com/swaggo/gin-swagger\"\n\n\t\"./docs\" // docs is generated by Swag CLI, you have to import it.\n)\n\n// @contact.name   API Support\n// @contact.url    http://www.swagger.io/support\n// @contact.email  support@swagger.io\n\n// @license.name  Apache 2.0\n// @license.url   http://www.apache.org/licenses/LICENSE-2.0.html\nfunc main() {\n\n\t// programmatically set swagger info\n\tdocs.SwaggerInfo.Title = \"Swagger Example API\"\n\tdocs.SwaggerInfo.Description = \"This is a sample server Petstore server.\"\n\tdocs.SwaggerInfo.Version = \"1.0\"\n\tdocs.SwaggerInfo.Host = \"petstore.swagger.io\"\n\tdocs.SwaggerInfo.BasePath = \"/v2\"\n\tdocs.SwaggerInfo.Schemes = []string{\"http\", \"https\"}\n\n\tr := gin.New()\n\n\t// use ginSwagger middleware to serve the API docs\n\tr.GET(\"/swagger/*any\", ginSwagger.WrapHandler(swaggerFiles.Handler))\n\n\tr.Run()\n}\n```\n\n3. Add [API Operation](#api-operation) annotations in `controller` code\n\n``` go\npackage controller\n\nimport (\n    \"fmt\"\n    \"net/http\"\n    \"strconv\"\n\n    \"github.com/gin-gonic/gin\"\n    \"github.com/swaggo/swag/example/celler/httputil\"\n    \"github.com/swaggo/swag/example/celler/model\"\n)\n\n// ShowAccount godoc\n// @Summary      Show an account\n// @Description  get string by ID\n// @Tags         accounts\n// @Accept       json\n// @Produce      json\n// @Param        id   path      int  true  \"Account ID\"\n// @Success      200  {object}  model.Account\n// @Failure      400  {object}  httputil.HTTPError\n// @Failure      404  {object}  httputil.HTTPError\n// @Failure      500  {object}  httputil.HTTPError\n// @Router       /accounts/{id} [get]\nfunc (c *Controller) ShowAccount(ctx *gin.Context) {\n  id := ctx.Param(\"id\")\n  aid, err := strconv.Atoi(id)\n  if err != nil {\n    httputil.NewError(ctx, http.StatusBadRequest, err)\n    return\n  }\n  account, err := model.AccountOne(aid)\n  if err != nil {\n    httputil.NewError(ctx, http.StatusNotFound, err)\n    return\n  }\n  ctx.JSON(http.StatusOK, account)\n}\n\n// ListAccounts godoc\n// @Summary      List accounts\n// @Description  get accounts\n// @Tags         accounts\n// @Accept       json\n// @Produce      json\n// @Param        q    query     string  false  \"name search by q\"  Format(email)\n// @Success      200  {array}   model.Account\n// @Failure      400  {object}  httputil.HTTPError\n// @Failure      404  {object}  httputil.HTTPError\n// @Failure      500  {object}  httputil.HTTPError\n// @Router       /accounts [get]\nfunc (c *Controller) ListAccounts(ctx *gin.Context) {\n  q := ctx.Request.URL.Query().Get(\"q\")\n  accounts, err := model.AccountsAll(q)\n  if err != nil {\n    httputil.NewError(ctx, http.StatusNotFound, err)\n    return\n  }\n  ctx.JSON(http.StatusOK, accounts)\n}\n//...\n```\n\n```console\nswag init\n```\n\n4. Run your app, and browse to http://localhost:8080/swagger/index.html. You will see Swagger 2.0 Api documents as shown below:\n\n![swagger_index.html](https://raw.githubusercontent.com/swaggo/swag/master/assets/swagger-image.png)\n\n## The swag formatter\n\nThe Swag Comments can be automatically formatted, just like 'go fmt'.\nFind the result of formatting [here](https://github.com/swaggo/swag/tree/master/example/celler).\n\nUsage:\n```shell\nswag fmt\n```\n\nExclude folder：\n```shell\nswag fmt -d ./ --exclude ./internal\n```\n\nWhen using `swag fmt`, you need to ensure that you have a doc comment for the function to ensure correct formatting.\nThis is due to `swag fmt` indenting swag comments with tabs, which is only allowed *after* a standard doc comment.\n\nFor example, use\n\n```go\n// ListAccounts lists all existing accounts\n//\n//  @Summary      List accounts\n//  @Description  get accounts\n//  @Tags         accounts\n//  @Accept       json\n//  @Produce      json\n//  @Param        q    query     string  false  \"name search by q\"  Format(email)\n//  @Success      200  {array}   model.Account\n//  @Failure      400  {object}  httputil.HTTPError\n//  @Failure      404  {object}  httputil.HTTPError\n//  @Failure      500  {object}  httputil.HTTPError\n//  @Router       /accounts [get]\nfunc (c *Controller) ListAccounts(ctx *gin.Context) {\n```\n\n## Implementation Status\n\n[Swagger 2.0 document](https://swagger.io/docs/specification/2-0/basic-structure/)\n\n- [x] Basic Structure\n- [x] API Host and Base Path\n- [x] Paths and Operations\n- [x] Describing Parameters\n- [x] Describing Request Body\n- [x] Describing Responses\n- [x] MIME Types\n- [x] Authentication\n  - [x] Basic Authentication\n  - [x] API Keys\n- [x] Adding Examples\n- [x] File Upload\n- [x] Enums\n- [x] Grouping Operations With Tags\n- [ ] Swagger Extensions\n\n# Declarative Comments Format\n\n## General API Info\n\n**Example**\n[celler/main.go](https://github.com/swaggo/swag/blob/master/example/celler/main.go)\n\n| annotation  | description                                | example                         |\n|-------------|--------------------------------------------|---------------------------------|\n| title       | **Required.** The title of the application.| // @title Swagger Example API   |\n| version     | **Required.** Provides the version of the application API.| // @version 1.0  |\n| description | A short description of the application.    |// @description This is a sample server celler server.         \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t |\n| tag.name    | Name of a tag.| // @tag.name This is the name of the tag                     |\n| tag.description   | Description of the tag  | // @tag.description Cool Description         |\n| tag.docs.url      | Url of the external Documentation of the tag | // @tag.docs.url https://example.com|\n| tag.docs.description  | Description of the external Documentation of the tag| // @tag.docs.description Best example documentation |\n| termsOfService | The Terms of Service for the API.| // @termsOfService http://swagger.io/terms/                     |\n| contact.name | The contact information for the exposed API.| // @contact.name API Support  |\n| contact.url  | The URL pointing to the contact information. MUST be in the format of a URL.  | // @contact.url http://www.swagger.io/support|\n| contact.email| The email address of the contact person/organization. MUST be in the format of an email address.| // @contact.email support@swagger.io                                   |\n| license.name | **Required.** The license name used for the API.|// @license.name Apache 2.0|\n| 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 |\n| host        | The host (name or ip) serving the API.     | // @host localhost:8080         |\n| BasePath    | The base path on which the API is served. | // @BasePath /api/v1             |\n| accept      | A list of MIME types the APIs can consume. Note that Accept only affects operations with a request body, such as POST, PUT and PATCH.  Value MUST be as described under [Mime Types](#mime-types).                     | // @accept json |\n| produce     | A list of MIME types the APIs can produce. Value MUST be as described under [Mime Types](#mime-types).                     | // @produce json |\n| query.collection.format | The default collection(array) param format in query,enums:csv,multi,pipes,tsv,ssv. If not set, csv is the default.| // @query.collection.format multi\n| schemes     | The transfer protocol for the operation that separated by spaces. | // @schemes http https |\n| externalDocs.description | Description of the external document. | // @externalDocs.description OpenAPI |\n| externalDocs.url         | URL of the external document. | // @externalDocs.url https://swagger.io/resources/open-api/ |\n| x-name      | The extension key, must be start by x- and take only json value | // @x-example-key {\"key\": \"value\"} |\n\n### Using markdown descriptions\nWhen a short string in your documentation is insufficient, or you need images, code examples and things like that you may want to use markdown descriptions. In order to use markdown descriptions use the following annotations.\n\n\n| annotation  | description                                | example                         |\n|-------------|--------------------------------------------|---------------------------------|\n| title       | **Required.** The title of the application.| // @title Swagger Example API   |\n| version     | **Required.** Provides the version of the application API.| // @version 1.0  |\n| description.markdown  | A short description of the application. Parsed from the api.md file. This is an alternative to @description    |// @description.markdown No value needed, this parses the description from api.md         \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t |\n| tag.name    | Name of a tag.| // @tag.name This is the name of the tag                     |\n| tag.description.markdown   | Description of the tag this is an alternative to tag.description. The description will be read from a file named like tagname.md  | // @tag.description.markdown         |\n| tag.x-name  | The extension key, must be start by x- and take only string value | // @x-example-key value |\n\n\n## API Operation\n\n**Example**\n[celler/controller](https://github.com/swaggo/swag/tree/master/example/celler/controller)\n\n\n| annotation           | description                                                                                                                                                                                       |\n|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| description          | A verbose explanation of the operation behavior.                                                                                                                                                  |\n| description.markdown | A short description of the application. The description will be read from a file.  E.g. `@description.markdown details` will load `details.md`                                                    | // @description.file endpoint.description.markdown  |\n| id                   | A unique string used to identify the operation. Must be unique among all API operations.                                                                                                          |\n| tags                 | A list of tags to each API operation that separated by commas.                                                                                                                                    |\n| summary              | A short summary of what the operation does.                                                                                                                                                       |\n| accept               | A list of MIME types the APIs can consume. Note that Accept only affects operations with a request body, such as POST, PUT and PATCH.  Value MUST be as described under [Mime Types](#mime-types). |\n| produce              | A list of MIME types the APIs can produce. Value MUST be as described under [Mime Types](#mime-types).                                                                                            |\n| param                | Parameters that separated by spaces. `param name`,`param type`,`data type`,`is mandatory?`,`comment` `attribute(optional)`                                                                        |\n| security             | [Security](#security) to each API operation.                                                                                                                                                      |\n| success              | Success response that separated by spaces. `return code or default`,`{param type}`,`data type`,`comment`                                                                                          |\n| failure              | Failure response that separated by spaces. `return code or default`,`{param type}`,`data type`,`comment`                                                                                          |\n| response             | As same as `success` and `failure`                                                                                                                                                                |\n| header               | Header in response that separated by spaces. `return code`,`{param type}`,`data type`,`comment`                                                                                                   |\n| router               | Path definition that separated by spaces. `path`,`[httpMethod]`                                                                                                                                   |\n| deprecatedrouter     | As same as router, but deprecated.                                                                                                                                                     |\n| x-name               | The extension key, must be start by x- and take only json value.                                                                                                                                  |\n| x-codeSample         | Optional Markdown usage. take `file` as parameter. This will then search for a file named like the summary in the given folder.                                                                   |\n| deprecated           | Mark endpoint as deprecated.                                                                                                                                                                      |\n\n\n\n## Mime Types\n\n`swag` accepts all MIME Types which are in the correct format, that is, match `*/*`.\nBesides that, `swag` also accepts aliases for some MIME Types as follows:\n\n| Alias                 | MIME Type                         |\n|-----------------------|-----------------------------------|\n| json                  | application/json                  |\n| xml                   | text/xml                          |\n| plain                 | text/plain                        |\n| html                  | text/html                         |\n| mpfd                  | multipart/form-data               |\n| x-www-form-urlencoded | application/x-www-form-urlencoded |\n| json-api              | application/vnd.api+json          |\n| json-stream           | application/x-json-stream         |\n| octet-stream          | application/octet-stream          |\n| png                   | image/png                         |\n| jpeg                  | image/jpeg                        |\n| gif                   | image/gif                         |\n| event-stream          | text/event-stream                 |\n\n\n\n## Param Type\n\n- query\n- path\n- header\n- body\n- formData\n\n## Data Type\n\n- string (string)\n- integer (int, uint, uint32, uint64)\n- number (float32)\n- boolean (bool)\n- file (param data type when uploading)\n- user defined struct\n\n## Security\n| annotation | description | parameters | example |\n|------------|-------------|------------|---------|\n| securitydefinitions.basic  | [Basic](https://swagger.io/docs/specification/2-0/authentication/basic-authentication/) auth.  |                                   | // @securityDefinitions.basic BasicAuth                      |\n| securitydefinitions.apikey | [API key](https://swagger.io/docs/specification/2-0/authentication/api-keys/) auth.            | in, name, description                          | // @securityDefinitions.apikey ApiKeyAuth                    |\n| securitydefinitions.oauth2.application  | [OAuth2 application](https://swagger.io/docs/specification/authentication/oauth2/) auth.       | tokenUrl, scope, description                   | // @securitydefinitions.oauth2.application OAuth2Application |\n| securitydefinitions.oauth2.implicit     | [OAuth2 implicit](https://swagger.io/docs/specification/authentication/oauth2/) auth.          | authorizationUrl, scope, description           | // @securitydefinitions.oauth2.implicit OAuth2Implicit       |\n| securitydefinitions.oauth2.password     | [OAuth2 password](https://swagger.io/docs/specification/authentication/oauth2/) auth.          | tokenUrl, scope, description                   | // @securitydefinitions.oauth2.password OAuth2Password       |\n| securitydefinitions.oauth2.accessCode   | [OAuth2 access code](https://swagger.io/docs/specification/authentication/oauth2/) auth.       | tokenUrl, authorizationUrl, scope, description | // @securitydefinitions.oauth2.accessCode OAuth2AccessCode   |\n\n\n| parameters annotation           | example                                                                 |\n|---------------------------------|-------------------------------------------------------------------------|\n| in                              | // @in header                                                           |\n| name                            | // @name Authorization                                                  |\n| tokenUrl                        | // @tokenUrl https://example.com/oauth/token                            |\n| authorizationurl                | // @authorizationurl https://example.com/oauth/authorize                |\n| scope.hoge                      | // @scope.write Grants write access                                     |\n| description                     | // @description OAuth protects our entity endpoints                     |\n\n## Attribute\n\n```go\n// @Param   enumstring  query     string     false  \"string enums\"       Enums(A, B, C)\n// @Param   enumint     query     int        false  \"int enums\"          Enums(1, 2, 3)\n// @Param   enumnumber  query     number     false  \"int enums\"          Enums(1.1, 1.2, 1.3)\n// @Param   string      query     string     false  \"string valid\"       minlength(5)  maxlength(10)\n// @Param   int         query     int        false  \"int valid\"          minimum(1)    maximum(10)\n// @Param   default     query     string     false  \"string default\"     default(A)\n// @Param   example     query     string     false  \"string example\"     example(string)\n// @Param   collection  query     []string   false  \"string collection\"  collectionFormat(multi)\n// @Param   extensions  query     []string   false  \"string collection\"  extensions(x-example=test,x-nullable)\n```\n\nIt also works for the struct fields:\n\n```go\ntype Foo struct {\n    Bar string `minLength:\"4\" maxLength:\"16\" example:\"random string\"`\n    Baz int `minimum:\"10\" maximum:\"20\" default:\"15\"`\n    Qux []string `enums:\"foo,bar,baz\"`\n}\n```\n\n### Available\n\nField Name | Type | Description\n---|:---:|---\n<a name=\"validate\"></a>validate | `string` | \tDetermines the validation for the parameter. Possible values are: `required,optional`.\n<a name=\"json\"></a>json | `string` | JSON tag options. The `omitempty` option will mark the field as not required.\n<a name=\"parameterDefault\"></a>default | * | Declares the value of the parameter that the server will use if none is provided, for example a \"count\" to control the number of results per page might default to 100 if not supplied by the client in the request. (Note: \"default\" has no meaning for required parameters.)  See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2. Unlike JSON Schema this value MUST conform to the defined [`type`](#parameterType) for this parameter.\n<a name=\"parameterMaximum\"></a>maximum | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.2.\n<a name=\"parameterMinimum\"></a>minimum | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.3.\n<a name=\"parameterMultipleOf\"></a>multipleOf | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.1.\n<a name=\"parameterMaxLength\"></a>maxLength | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.1.\n<a name=\"parameterMinLength\"></a>minLength | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.2.\n<a name=\"parameterEnums\"></a>enums | [\\*] | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1.\n<a name=\"parameterFormat\"></a>format | `string` | The extending format for the previously mentioned [`type`](#parameterType). See [Data Type Formats](https://swagger.io/specification/v2/#dataTypeFormat) for further details.\n<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&#124;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`.\n<a name=\"parameterExample\"></a>example | * | Declares the example for the parameter value\n<a name=\"parameterExtensions\"></a>extensions | `string` | Add extension to parameters.\n\n### Future\n\nField Name | Type | Description\n---|:---:|---\n<a name=\"parameterPattern\"></a>pattern | `string` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.\n<a name=\"parameterMaxItems\"></a>maxItems | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.2.\n<a name=\"parameterMinItems\"></a>minItems | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.3.\n<a name=\"parameterUniqueItems\"></a>uniqueItems | `boolean` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.4.\n\n## Examples\n\n### Descriptions over multiple lines\n\nYou can add descriptions spanning multiple lines in either the general api description or routes definitions like so:\n\n```go\n// @description This is the first line\n// @description This is the second line\n// @description And so forth.\n```\n\n### User defined structure with an array type\n\n```go\n// @Success 200 {array} model.Account <-- This is a user defined struct.\n```\n\n```go\npackage model\n\ntype Account struct {\n    ID   int    `json:\"id\" example:\"1\"`\n    Name string `json:\"name\" example:\"account name\"`\n}\n```\n\n\n### Function scoped struct declaration\n\nYou can declare your request response structs inside a function body.\nYou must have to follow the naming convention `<package-name>.<function-name>.<struct-name> `.\n\n```go\npackage main\n\n// @Param request body main.MyHandler.request true \"query params\"\n// @Success 200 {object} main.MyHandler.response\n// @Router /test [post]\nfunc MyHandler() {\n\ttype request struct {\n\t\tRequestField string\n\t}\n\n\ttype response struct {\n\t\tResponseField string\n\t}\n}\n```\n\n\n### Model composition in response\n```go\n// JSONResult's data field will be overridden by the specific type proto.Order\n@success 200 {object} jsonresult.JSONResult{data=proto.Order} \"desc\"\n```\n\n```go\ntype JSONResult struct {\n    Code    int          `json:\"code\" `\n    Message string       `json:\"message\"`\n    Data    interface{}  `json:\"data\"`\n}\n\ntype Order struct { //in `proto` package\n    Id  uint            `json:\"id\"`\n    Data  interface{}   `json:\"data\"`\n}\n```\n\n- also support array of objects and primitive types as nested response\n```go\n@success 200 {object} jsonresult.JSONResult{data=[]proto.Order} \"desc\"\n@success 200 {object} jsonresult.JSONResult{data=string} \"desc\"\n@success 200 {object} jsonresult.JSONResult{data=[]string} \"desc\"\n```\n\n- overriding multiple fields. field will be added if not exists\n```go\n@success 200 {object} jsonresult.JSONResult{data1=string,data2=[]string,data3=proto.Order,data4=[]proto.Order} \"desc\"\n```\n- overriding deep-level fields\n```go\ntype DeepObject struct { //in `proto` package\n\t...\n}\n@success 200 {object} jsonresult.JSONResult{data1=proto.Order{data=proto.DeepObject},data2=[]proto.Order{data=[]proto.DeepObject}} \"desc\"\n```\n### Add request headers\n\n```go\n// @Param        X-MyHeader\t  header    string    true   \t\"MyHeader must be set for valid response\"\n// @Param        X-API-VERSION    header    string    true   \t\"API version eg.: 1.0\"\n```\n\n### Add response headers\n\n```go\n// @Success      200              {string}  string    \"ok\"\n// @failure      400              {string}  string    \"error\"\n// @response     default          {string}  string    \"other error\"\n// @Header       200              {string}  Location  \"/entity/1\"\n// @Header       200,400,default  {string}  Token     \"token\"\n// @Header       all              {string}  Token2    \"token2\"\n```\n\n### Use multiple path params\n\n```go\n/// ...\n// @Param group_id   path int true \"Group ID\"\n// @Param account_id path int true \"Account ID\"\n// ...\n// @Router /examples/groups/{group_id}/accounts/{account_id} [get]\n```\n\n### Add multiple paths\n\n```go\n/// ...\n// @Param group_id path int true \"Group ID\"\n// @Param user_id  path int true \"User ID\"\n// ...\n// @Router /examples/groups/{group_id}/user/{user_id}/address [put]\n// @Router /examples/user/{user_id}/address [put]\n```\n\n### Example value of struct\n\n```go\ntype Account struct {\n    ID   int    `json:\"id\" example:\"1\"`\n    Name string `json:\"name\" example:\"account name\"`\n    PhotoUrls []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n}\n```\n\n### SchemaExample of body\n\n```go\n// @Param email body string true \"message/rfc822\" SchemaExample(Subject: Testmail\\r\\n\\r\\nBody Message\\r\\n)\n```\n\n### Description of struct\n\n```go\n// Account model info\n// @Description User account information\n// @Description with user id and username\ntype Account struct {\n\t// ID this is userid\n\tID   int    `json:\"id\"`\n\tName string `json:\"name\"` // This is Name\n}\n```\n\n[#708](https://github.com/swaggo/swag/issues/708) The parser handles only struct comments starting with `@Description` attribute.\nBut it writes all struct field comments as is.\n\nSo, generated swagger doc as follows:\n```json\n\"Account\": {\n  \"type\":\"object\",\n  \"description\": \"User account information with user id and username\"\n  \"properties\": {\n    \"id\": {\n      \"type\": \"integer\",\n      \"description\": \"ID this is userid\"\n    },\n    \"name\": {\n      \"type\":\"string\",\n      \"description\": \"This is Name\"\n    }\n  }\n}\n```\n\n### Use swaggertype tag to supported custom type\n[#201](https://github.com/swaggo/swag/issues/201#issuecomment-475479409)\n\n```go\ntype TimestampTime struct {\n    time.Time\n}\n\n///implement encoding.JSON.Marshaler interface\nfunc (t *TimestampTime) MarshalJSON() ([]byte, error) {\n    bin := make([]byte, 16)\n    bin = strconv.AppendInt(bin[:0], t.Time.Unix(), 10)\n    return bin, nil\n}\n\nfunc (t *TimestampTime) UnmarshalJSON(bin []byte) error {\n    v, err := strconv.ParseInt(string(bin), 10, 64)\n    if err != nil {\n        return err\n    }\n    t.Time = time.Unix(v, 0)\n    return nil\n}\n///\n\ntype Account struct {\n    // Override primitive type by simply specifying it via `swaggertype` tag\n    ID     sql.NullInt64 `json:\"id\" swaggertype:\"integer\"`\n\n    // Override struct type to a primitive type 'integer' by specifying it via `swaggertype` tag\n    RegisterTime TimestampTime `json:\"register_time\" swaggertype:\"primitive,integer\"`\n\n    // Array types can be overridden using \"array,<prim_type>\" format\n    Coeffs []big.Float `json:\"coeffs\" swaggertype:\"array,number\"`\n}\n```\n\n[#379](https://github.com/swaggo/swag/issues/379)\n```go\ntype CerticateKeyPair struct {\n\tCrt []byte `json:\"crt\" swaggertype:\"string\" format:\"base64\" example:\"U3dhZ2dlciByb2Nrcw==\"`\n\tKey []byte `json:\"key\" swaggertype:\"string\" format:\"base64\" example:\"U3dhZ2dlciByb2Nrcw==\"`\n}\n```\ngenerated swagger doc as follows:\n```go\n\"api.MyBinding\": {\n  \"type\":\"object\",\n  \"properties\":{\n    \"crt\":{\n      \"type\":\"string\",\n      \"format\":\"base64\",\n      \"example\":\"U3dhZ2dlciByb2Nrcw==\"\n    },\n    \"key\":{\n      \"type\":\"string\",\n      \"format\":\"base64\",\n      \"example\":\"U3dhZ2dlciByb2Nrcw==\"\n    }\n  }\n}\n\n```\n\n### Use global overrides to support a custom type\n\nIf you are using generated files, the [`swaggertype`](#use-swaggertype-tag-to-supported-custom-type) or `swaggerignore` tags may not be possible.\n\nBy passing a mapping to swag with `--overridesFile` you can tell swag to use one type in place of another wherever it appears. By default, if a `.swaggo` file is present in the current directory it will be used.\n\nGo code:\n```go\ntype MyStruct struct {\n  ID     sql.NullInt64 `json:\"id\"`\n  Name   sql.NullString `json:\"name\"`\n}\n```\n\n`.swaggo`:\n```\n// Replace all NullInt64 with int\nreplace database/sql.NullInt64 int\n\n// Don't include any fields of type database/sql.NullString in the swagger docs\nskip    database/sql.NullString\n```\n\nPossible directives are comments (beginning with `//`), `replace path/to/a.type path/to/b.type`, and `skip path/to/a.type`.\n\n(Note that the full paths to any named types must be provided to prevent problems when multiple packages define a type with the same name)\n\nRendered:\n```go\n\"types.MyStruct\": {\n  \"id\": \"integer\"\n}\n```\n\n\n### Use swaggerignore tag to exclude a field\n\n```go\ntype Account struct {\n    ID   string    `json:\"id\"`\n    Name string     `json:\"name\"`\n    Ignored int     `swaggerignore:\"true\"`\n}\n```\n\n### Add extension info to struct field\n\n```go\ntype Account struct {\n    ID   string    `json:\"id\"   extensions:\"x-nullable,x-abc=def,!x-omitempty\"` // extensions fields must start with \"x-\"\n}\n```\n\ngenerate swagger doc as follows:\n\n```go\n\"Account\": {\n    \"type\": \"object\",\n    \"properties\": {\n        \"id\": {\n            \"type\": \"string\",\n            \"x-nullable\": true,\n            \"x-abc\": \"def\",\n            \"x-omitempty\": false\n        }\n    }\n}\n```\n### Rename model to display\n\n```golang\ntype Resp struct {\n\tCode int\n}//@name Response\n```\n\n### How to use security annotations\n\nGeneral API info.\n\n```go\n// @securityDefinitions.basic BasicAuth\n\n// @securitydefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n```\n\nEach API operation.\n\n```go\n// @Security ApiKeyAuth\n```\n\nMake it OR condition\n\n```go\n// @Security ApiKeyAuth\n// @Security OAuth2Application[write, admin]\n```\n\nMake it AND condition\n\n```go\n// @Security ApiKeyAuth && firebase\n// @Security OAuth2Application[write, admin] && APIKeyAuth\n```\n\n### Generate enum types from enum constants\n\nYou can generate enums from ordered constants. Each enum variant can have a comment, an override name, or both. This works with both iota-defined and manually defined constants.\n\n```go\ntype Difficulty string\n\nconst (\n\tEasy   Difficulty = \"easy\" // You can add a comment to the enum variant.\n\tMedium Difficulty = \"medium\" // @name MediumDifficulty\n\tHard   Difficulty = \"hard\" // @name HardDifficulty You can have a name override and a comment.\n)\n\ntype Class int\n\nconst (\n\tFirst Class = iota // @name FirstClass\n\tSecond // Name override and comment rules apply here just as above.\n\tThird // @name ThirdClass This one has a name override and a comment.\n)\n\n// There is no need to add `enums:\"...\"` to the fields, it is automatically generated from the ordered consts.\ntype Quiz struct {\n\tDifficulty Difficulty\n\tClass Class\n\tQuestions []string\n\tAnswers []string\n}\n```\n\n\n### Add a description for enum items\n\n```go\ntype Example struct {\n\t// Sort order:\n\t// * asc - Ascending, from A to Z.\n\t// * desc - Descending, from Z to A.\n\tOrder string `enums:\"asc,desc\"`\n}\n```\n\n### Generate only specific docs file types\n\nBy default `swag` command generates Swagger specification in three different files/file types:\n- docs.go\n- swagger.json\n- swagger.yaml\n\nIf you would like to limit a set of file types which should be generated you can use `--outputTypes` (short `-ot`) flag. Default value is `go,json,yaml` - output types separated with comma. To limit output only to `go` and `yaml` files, you would write `go,yaml`. With complete command that would be `swag init --outputTypes go,yaml`.\n\n### How to use Generics\n\n```go\n// @Success 200 {object} web.GenericNestedResponse[types.Post]\n// @Success 204 {object} web.GenericNestedResponse[types.Post, Types.AnotherOne]\n// @Success 201 {object} web.GenericNestedResponse[web.GenericInnerType[types.Post]]\nfunc GetPosts(w http.ResponseWriter, r *http.Request) {\n\t_ = web.GenericNestedResponse[types.Post]{}\n}\n```\nSee [this file](https://github.com/swaggo/swag/blob/master/testdata/generics_nested/api/api.go) for more details\nand other examples.\n\n### Change the default Go Template action delimiters\n[#980](https://github.com/swaggo/swag/issues/980)\n[#1177](https://github.com/swaggo/swag/issues/1177)\n\nIf your swagger annotations or struct fields contain \"{{\" or \"}}\", the template generation will most likely fail, as these are the default delimiters for [go templates](https://pkg.go.dev/text/template#Template.Delims).\n\nTo make the generation work properly, you can change the default delimiters with `-td`. For example:\n```console\nswag init -g http/api.go -td \"[[,]]\"\n```\nThe new delimiter is a string with the format \"`<left delimiter>`,`<right delimiter>`\".\n\n### Parse Internal and Dependency Packages\n\nIf the struct is defined in a dependency package, use `--parseDependency`.\n\nIf the struct is defined in your main project, use `--parseInternal`.\n\nif you want to include both internal and from dependencies use both flags\n```\nswag init --parseDependency --parseInternal\n```\n\n## About the Project\nThis 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).\n## Contributors\n\nThis project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].\n<a href=\"https://github.com/swaggo/swag/graphs/contributors\"><img src=\"https://opencollective.com/swag/contributors.svg?width=890&button=false\" /></a>\n\n\n## Backers\n\nThank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/swag#backer)]\n\n<a href=\"https://opencollective.com/swag#backers\" target=\"_blank\"><img src=\"https://opencollective.com/swag/backers.svg?width=890\"></a>\n\n\n## Sponsors\n\nSupport 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)]\n\n<a href=\"https://opencollective.com/swag/sponsor/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/9/avatar.svg\"></a>\n\n\n\n\n## License\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fswaggo%2Fswag.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fswaggo%2Fswag?ref=badge_large)\n"
  },
  {
    "path": "README_pt.md",
    "content": "# swag\n\n🌍 *[English](README.md) ∙ [简体中文](README_zh-CN.md) ∙ [Português](README_pt.md)*\n\n<img align=\"right\" width=\"180px\" src=\"https://raw.githubusercontent.com/swaggo/swag/master/assets/swaggo.png\">\n\n[![Build Status](https://github.com/swaggo/swag/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/features/actions)\n[![Coverage Status](https://img.shields.io/codecov/c/github/swaggo/swag/master.svg)](https://codecov.io/gh/swaggo/swag)\n[![Go Report Card](https://goreportcard.com/badge/github.com/swaggo/swag)](https://goreportcard.com/report/github.com/swaggo/swag)\n[![codebeat badge](https://codebeat.co/badges/71e2f5e5-9e6b-405d-baf9-7cc8b5037330)](https://codebeat.co/projects/github-com-swaggo-swag-master)\n[![Go Doc](https://godoc.org/github.com/swaggo/swagg?status.svg)](https://godoc.org/github.com/swaggo/swag)\n[![Backers on Open Collective](https://opencollective.com/swag/backers/badge.svg)](#backers)\n[![Sponsors on Open Collective](https://opencollective.com/swag/sponsors/badge.svg)](#sponsors) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fswaggo%2Fswag.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fswaggo%2Fswag?ref=badge_shield)\n[![Release](https://img.shields.io/github/release/swaggo/swag.svg?style=flat-square)](https://github.com/swaggo/swag/releases)\n\nSwag converte anotações Go para Documentação Swagger 2.0. Criámos uma variedade de plugins para populares [Go web frameworks](#supported-web-frameworks). Isto permite uma integração rápida com um projecto Go existente (utilizando a Swagger UI).\n\n## Conteúdo\n- [Começando](#começando)\n - [Estruturas Web Suportadas](#estruturas-web-suportadas)\n - [Como utilizá-lo com Gin](#como-como-ser-como-gin)\n - [O formatador de swag](#a-formatação-de-swag)\n - [Estado de Implementação](#implementação-estado)\n - [Formato dos comentários declarativos](#formato-dos-comentarios-declarativos)\n\t- [Informações Gerais API](#informações-gerais-api)\n\t- [Operação API](#api-operacao)\n\t- [Segurança](#seguranca)\n - [Exemplos](#exemplos)\n    - [Descrições em múltiplas linhas](#descricoes-sobre-múltiplas-linhas)\n\t- [Estrutura definida pelo utilizador com um tipo de matriz](#-estrutura-definida-pelo-utilizador-com-um-um-tipo)\n\t- [Declaração de estruturação de funções](#function-scoped-struct-declaration)\n\t- [Composição do modelo em resposta](#model-composição-em-resposta)\n\t- [Adicionar um cabeçalho em resposta](#add-a-headers-in-response)\n\t- [Utilizar parâmetros de caminhos múltiplos](#use-multiple-path-params)\n\t- [Exemplo de valor de estrutura](#exemplo-do-valor-de-estrutura)\n\t- [Schema Exemplo do corpo](#schemaexample-of-body)\n\t- [Descrição da estrutura](#descrição-da-estrutura)\n\t- [Usar etiqueta do tipo swaggertype para suportar o tipo personalizado](#use-swaggertype-tag-to-supported-custom-type)\n\t- [Utilizar anulações globais para suportar um tipo personalizado](#use-global-overrides-to-support-a-custom-type)\n\t- [Use swaggerignore tag para excluir um campo](#use-swaggerignore-tag-to-excluir-um-campo)\n\t- [Adicionar informações de extensão ao campo de estruturação](#add-extension-info-to-struct-field)\n\t- [Renomear modelo a expor](#renome-modelo-a-exibir)\n\t- [Como utilizar as anotações de segurança](#como-utilizar-as-anotações-de-segurança)\n\t- [Adicionar uma descrição para enumerar artigos](#add-a-description-for-enum-items)\n\t- [Gerar apenas tipos de ficheiros de documentos específicos](#generate-only-specific-docs-file-file-types)\n    - [Como usar tipos genéricos](#como-usar-tipos-genéricos)\n- [Sobre o projecto](#sobre-o-projecto)\n\n## Começando\n\n1. Adicione comentários ao código-fonte da API, consulte [Formato dos comentários declarativos](#declarative-comments-format).\n\n2. Descarregue o swag utilizando:\n```sh\ngo install github.com/swaggo/swag/cmd/swag@latest\n```\nPara construir a partir da fonte é necessário [Go](https://golang.org/dl/) (1.19 ou mais recente).\n\nOu descarregar um binário pré-compilado a partir da [página de lançamento](https://github.com/swaggo/swag/releases).\n\n3. Executar `swag init` na pasta raiz do projecto que contém o ficheiro `main.go`. Isto irá analisar os seus comentários e gerar os ficheiros necessários (pasta `docs` e `docs/docs.go`).\n```sh\nswag init\n```\n\nCertifique-se de importar os `docs/docs.go` gerados para que a sua configuração específica fique \"init\" ed. Se as suas anotações API gerais não viverem em `main.go`, pode avisar a swag com a bandeira `-g`.\n```sh\nswag init -g http/api.go\n```\n\n4. (opcional) Utilizar o formato `swag fmt` no comentário SWAG. (Por favor, actualizar para a versão mais recente)\n\n```sh\nswag fmt\n```\n\n## swag cli\n\n```sh\nswag init -h\nNOME:\n   swag init - Criar docs.go\n\nUTILIZAÇÃO:\n   swag init [opções de comando] [argumentos...]\n\nOPÇÕES:\n   --quiet, -q Fazer o logger ficar quiet (por padrão: falso)\n   --generalInfo valor, -g valor Go caminho do ficheiro em que 'swagger general API Info' está escrito (por padrão: \"main.go\")\n   --dir valor, -d valor Os directórios que deseja analisar, separados por vírgulas e de informação geral devem estar no primeiro (por padrão: \"./\")\n   --exclude valor Excluir directórios e ficheiros ao pesquisar, separados por vírgulas\n   -propertyStrategy da estratégia, -p valor da propriedadeEstratégia de nomeação de propriedades como snakecase,camelcase,pascalcase (por padrão: \"camelcase\")\n   --output de saída, -o valor directório de saída para todos os ficheiros gerados(swagger.json, swagger.yaml e docs.go) (por padrão: \"./docs\")\n   --outputTypes valor de saídaTypes, -- valor de saída Tipos de ficheiros gerados (docs.go, swagger.json, swagger.yaml) como go,json,yaml (por padrão: \"go,json,yaml\")\n   --parseVendor ParseVendor Parse go files na pasta 'vendor', desactivado por padrão (padrão: falso)\n   --parseInternal Parse go ficheiros em pacotes internos, desactivados por padrão (padrão: falso)\n   --generatedTime Gerar timestamp no topo dos docs.go, desactivado por padrão (padrão: falso)\n   --parteDepth value Dependência profundidade parse (por padrão: 100)\n   --templateDelims value, --td value fornecem delimitadores personalizados para a geração de modelos Go. O formato é leftDelim,rightDelim. Por exemplo: \"[[,]]\"\n   ...\n\n   --help, -h mostrar ajuda (por padrão: falso)\n```\n\n```bash\nswag fmt -h\nNOME:\n   swag fmt - formato swag comentários\n\nUTILIZAÇÃO:\n   swag fmt [opções de comando] [argumentos...]\n\nOPÇÕES:\n   --dir valor, -d valor Os directórios que pretende analisar, separados por vírgulas e de informação geral devem estar no primeiro (por padrão: \"./\")\n   --excluir valor Excluir directórios e ficheiros ao pesquisar, separados por vírgulas\n   --generalInfo value, -g value Go file path in which 'swagger general API Info' is written (por padrão: \"main.go\")\n   --ajuda, -h mostrar ajuda (por padrão: falso)\n\n```\n\n## Estruturas Web Suportadas\n\n- [gin](http://github.com/swaggo/gin-swagger)\n- [echo](http://github.com/swaggo/echo-swagger)\n- [buffalo](https://github.com/swaggo/buffalo-swagger)\n- [net/http](https://github.com/swaggo/http-swagger)\n- [gorilla/mux](https://github.com/swaggo/http-swagger)\n- [go-chi/chi](https://github.com/swaggo/http-swagger)\n- [flamingo](https://github.com/i-love-flamingo/swagger)\n- [fiber](https://github.com/gofiber/swagger)\n- [atreugo](https://github.com/Nerzal/atreugo-swagger)\n- [hertz](https://github.com/hertz-contrib/swagger)\n\n## Como utilizá-lo com Gin\n\nEncontrar o código fonte de exemplo [aqui](https://github.com/swaggo/swag/tree/master/example/celler).\n\n1. Depois de utilizar `swag init` para gerar os documentos Swagger 2.0, importar os seguintes pacotes:\n```go\nimport \"github.com/swaggo/gin-swagger\" // gin-swagger middleware\nimport \"github.com/swaggo/files\" // swagger embed files\n```\n\n2. Adicionar [Informações Gerais API](#general-api-info) anotações em código `main.go`:\n\n\n```go\n// @title           Swagger Example API\n// @version         1.0\n// @description     This is a sample server celler server.\n// @termsOfService  http://swagger.io/terms/\n\n// @contact.name   API Support\n// @contact.url    http://www.swagger.io/support\n// @contact.email  support@swagger.io\n\n// @license.name  Apache 2.0\n// @license.url   http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host      localhost:8080\n// @BasePath  /api/v1\n\n// @securityDefinitions.basic  BasicAuth\n\n// @externalDocs.description  OpenAPI\n// @externalDocs.url          https://swagger.io/resources/open-api/\nfunc main() {\n\tr := gin.Default()\n\n\tc := controller.NewController()\n\n\tv1 := r.Group(\"/api/v1\")\n\t{\n\t\taccounts := v1.Group(\"/accounts\")\n\t\t{\n\t\t\taccounts.GET(\":id\", c.ShowAccount)\n\t\t\taccounts.GET(\"\", c.ListAccounts)\n\t\t\taccounts.POST(\"\", c.AddAccount)\n\t\t\taccounts.DELETE(\":id\", c.DeleteAccount)\n\t\t\taccounts.PATCH(\":id\", c.UpdateAccount)\n\t\t\taccounts.POST(\":id/images\", c.UploadAccountImage)\n\t\t}\n    //...\n\t}\n\tr.GET(\"/swagger/*any\", ginSwagger.WrapHandler(swaggerFiles.Handler))\n\tr.Run(\":8080\")\n}\n//...\n```\n\nAlém disso, algumas informações API gerais podem ser definidas de forma dinâmica. O pacote de código gerado `docs` exporta a variável `SwaggerInfo` que podemos utilizar para definir programticamente o título, descrição, versão, hospedeiro e caminho base. Exemplo utilizando Gin:\n\n```go\npackage main\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/swaggo/files\"\n\t\"github.com/swaggo/gin-swagger\"\n\n\t\"./docs\" // docs is generated by Swag CLI, you have to import it.\n)\n\n// @contact.name   API Support\n// @contact.url    http://www.swagger.io/support\n// @contact.email  support@swagger.io\n\n// @license.name  Apache 2.0\n// @license.url   http://www.apache.org/licenses/LICENSE-2.0.html\nfunc main() {\n\n\t// programmatically set swagger info\n\tdocs.SwaggerInfo.Title = \"Swagger Example API\"\n\tdocs.SwaggerInfo.Description = \"This is a sample server Petstore server.\"\n\tdocs.SwaggerInfo.Version = \"1.0\"\n\tdocs.SwaggerInfo.Host = \"petstore.swagger.io\"\n\tdocs.SwaggerInfo.BasePath = \"/v2\"\n\tdocs.SwaggerInfo.Schemes = []string{\"http\", \"https\"}\n\n\tr := gin.New()\n\n\t// use ginSwagger middleware to serve the API docs\n\tr.GET(\"/swagger/*any\", ginSwagger.WrapHandler(swaggerFiles.Handler))\n\n\tr.Run()\n}\n```\n\n3. Adicionar [Operação API](#api-operacao) anotações em código `controller`\n\n```go\npackage controller\n\nimport (\n    \"fmt\"\n    \"net/http\"\n    \"strconv\"\n\n    \"github.com/gin-gonic/gin\"\n    \"github.com/swaggo/swag/example/celler/httputil\"\n    \"github.com/swaggo/swag/example/celler/model\"\n)\n\n// ShowAccount godoc\n// @Summary      Show an account\n// @Description  get string by ID\n// @Tags         accounts\n// @Accept       json\n// @Produce      json\n// @Param        id   path      int  true  \"Account ID\"\n// @Success      200  {object}  model.Account\n// @Failure      400  {object}  httputil.HTTPError\n// @Failure      404  {object}  httputil.HTTPError\n// @Failure      500  {object}  httputil.HTTPError\n// @Router       /accounts/{id} [get]\nfunc (c *Controller) ShowAccount(ctx *gin.Context) {\n  id := ctx.Param(\"id\")\n  aid, err := strconv.Atoi(id)\n  if err != nil {\n    httputil.NewError(ctx, http.StatusBadRequest, err)\n    return\n  }\n  account, err := model.AccountOne(aid)\n  if err != nil {\n    httputil.NewError(ctx, http.StatusNotFound, err)\n    return\n  }\n  ctx.JSON(http.StatusOK, account)\n}\n\n// ListAccounts godoc\n// @Summary      List accounts\n// @Description  get accounts\n// @Tags         accounts\n// @Accept       json\n// @Produce      json\n// @Param        q    query     string  false  \"name search by q\"  Format(email)\n// @Success      200  {array}   model.Account\n// @Failure      400  {object}  httputil.HTTPError\n// @Failure      404  {object}  httputil.HTTPError\n// @Failure      500  {object}  httputil.HTTPError\n// @Router       /accounts [get]\nfunc (c *Controller) ListAccounts(ctx *gin.Context) {\n  q := ctx.Request.URL.Query().Get(\"q\")\n  accounts, err := model.AccountsAll(q)\n  if err != nil {\n    httputil.NewError(ctx, http.StatusNotFound, err)\n    return\n  }\n  ctx.JSON(http.StatusOK, accounts)\n}\n//...\n```\n\n```console\nswag init\n```\n\n4. Execute a sua aplicação, e navegue para http://localhost:8080/swagger/index.html. Verá os documentos Swagger 2.0 Api, como mostrado abaixo:\n\n![swagger_index.html](https://raw.githubusercontent.com/swaggo/swag/master/assets/swagger-image.png)\n\n## O formatador de swag\n\nOs Swag Comments podem ser formatados automaticamente, assim como 'go fmt'.\nEncontre o resultado da formatação [aqui](https://github.com/swaggo/swag/tree/master/example/celler).\n\nUsage:\n```shell\nswag fmt\n```\n\nExclude folder：\n```shell\nswag fmt -d ./ --exclude ./internal\n```\n\nAo utilizar `swag fmt`, é necessário assegurar-se de que tem um comentário doc para a função a fim de assegurar uma formatação correcta.\nIsto deve-se ao `swag fmt` que traça comentários swag com separadores, o que só é permitido *após* um comentário doc padrão.\n\nPor exemplo, utilizar\n\n```go\n// ListAccounts lists all existing accounts\n//\n//  @Summary      List accounts\n//  @Description  get accounts\n//  @Tags         accounts\n//  @Accept       json\n//  @Produce      json\n//  @Param        q    query     string  false  \"name search by q\"  Format(email)\n//  @Success      200  {array}   model.Account\n//  @Failure      400  {object}  httputil.HTTPError\n//  @Failure      404  {object}  httputil.HTTPError\n//  @Failure      500  {object}  httputil.HTTPError\n//  @Router       /accounts [get]\nfunc (c *Controller) ListAccounts(ctx *gin.Context) {\n```\n\n## Estado de Implementação\n\n[Documento Swagger 2.0](https://swagger.io/docs/specification/2-0/basic-structure/)\n\n- [x] Estrutura básica\n- [x] Hospedeiro API e Caminho Base\n- [x] Caminhos e operações\n- [x] Descrição dos parâmetros\n- [x] Descrever o corpo do pedido\n- [x] Descrição das respostas\n- [x] Tipos MIME\n- [x] Autenticação\n  - [x] Autenticação básica\n  - [x] Chaves API\n- [x] Acrescentar exemplos\n- [x] Carregamento de ficheiros\n- [x] Enums\n- [x] Operações de Agrupamento com Etiquetas\n- Extensões Swagger\n\n## Formato dos comentários declarativos\n\n## Informações Gerais API\n\n**Exemplo**\n[celler/main.go](https://github.com/swaggo/swag/blob/master/example/celler/main.go)\n\n| anotação | descrição | exemplo |\n|-------------|--------------------------------------------|---------------------------------|\n| title | **Obrigatório.** O título da aplicação.| // @title Swagger Example API |\n| version | **Obrigatório.** Fornece a versão da aplicação API.| // @version 1.0 |\n| description | Uma breve descrição da candidatura.    |// @descrição Este é um servidor servidor de celas de amostra.         \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t |\n| tag.name | Nome de uma tag.| // @tag.name Este é o nome da tag |\n| tag.description | Descrição da tag | // @tag.description Cool Description |\n| tag.docs.url | Url da Documentação externa da tag | // @tag.docs.url https://example.com|\n| tag.docs.description | Descrição da documentação externa da tag| // @tag.docs.description Melhor exemplo de documentação |\n| TermsOfService | Os Termos de Serviço para o API.| // @termsOfService http://swagger.io/terms/ |\n| contact.name | A informação de contacto para a API exposta.| // @contacto.name Suporte API |\n| contact.url | O URL que aponta para as informações de contacto. DEVE estar no formato de um URL.  | // @contact.url http://www.swagger.io/support|\n| contact.email| O endereço de email da pessoa/organização de contacto. DEVE estar no formato de um endereço de correio electrónico.| // @contact.email support@swagger.io |\n| license.name | **Obrigatório.** O nome da licença utilizada para a API.|// @licença.name Apache 2.0|\n| license.url | Um URL para a licença utilizada para a API. DEVE estar no formato de um URL.                       | // @license.url http://www.apache.org/licenses/LICENSE-2.0.html |\n| host | O anfitrião (nome ou ip) que serve o API.     | // @host localhost:8080 |\n| BasePath | O caminho de base sobre o qual o API é servido. | // @BasePath /api/v1 |\n| accept | Uma lista de tipos de MIME que os APIs podem consumir. Note que accept só afecta operações com um organismo de pedido, tais como POST, PUT e PATCH.  O valor DEVE ser o descrito em [Tipos de Mime](#mime-types).                     | // @accept json |\n| produce | Uma lista de tipos de MIME que os APIs podem produce. O valor DEVE ser o descrito em [Tipos de Mime](#mime-types).                     | // @produce json |\n| query.collection.format | O formato padrão de param de colecção(array) em query,enums:csv,multi,pipes,tsv,ssv. Se não definido, csv é o padrão.| // @query.collection.format multi\n| schemes | O protocolo de transferência para a operação que separou por espaços. | // @schemes http https |\n| externalDocs.description | Descrição do documento externo. | // @externalDocs.description OpenAPI |\n| externalDocs.url | URL do documento externo. | // @externalDocs.url https://swagger.io/resources/open-api/ |\n| x-name | A chave de extensão, deve ser iniciada por x- e tomar apenas o valor json | // @x-example-key {\"chave\": \"valor\"} |\n\n### Usando descrições de remarcação para baixo\nQuando uma pequena sequência na sua documentação é insuficiente, ou precisa de imagens, exemplos de códigos e coisas do género, pode querer usar descrições de marcação. Para utilizar as descrições markdown, utilize as seguintes anotações.\n\n| anotação | descrição | exemplo |\n|-------------|--------------------------------------------|---------------------------------|\n| title | **Obrigatório.** O título da aplicação.| // @title Swagger Example API |\n| version | **Obrigatório.** Fornece a versão da aplicação API.| // @versão 1.0 |\n| description.markdown | Uma breve descrição da candidatura. Parsed a partir do ficheiro api.md. Esta é uma alternativa a @description |// @description.markdown Sem valor necessário, isto analisa a descrição do ficheiro api.md |.\n| tag.name | Nome de uma tag.| // @tag.name Este é o nome da tag |\n| tag.description.markdown | Descrição da tag esta é uma alternativa à tag.description. A descrição será lida a partir de um ficheiro nomeado como tagname.md | // @tag.description.markdown |\n\n## Operação API\n\n**Exemplo**\n[celler/controller](https://github.com/swaggo/swag/tree/master/example/celler/controller)\n\n| anotação | descrição |\n|-------------|----------------------------------------------------------------------------------------------------------------------------|\n| descrição | Uma explicação verbosa do comportamento da operação.                                                                           |\n| description.markdown | Uma breve descrição da candidatura. A descrição será lida a partir de um ficheiro.  Por exemplo, `@description.markdown details` irá carregar `details.md`| // @description.file endpoint.description.markdown |\n| id | Um fio único utilizado para identificar a operação. Deve ser única entre todas as operações API.                                   |\n| tags | Uma lista de tags para cada operação API que separou por vírgulas.                                                             |\n| summary | Um breve resumo do que a operação faz.                                                                                |\n| accept | Uma lista de tipos de MIME que os APIs podem consumir. Note que accept só afecta operações com um organismo de pedido, tais como POST, PUT e PATCH.  O valor DEVE ser o descrito em [Tipos de Mime](#mime-types).                     |\n| produce | Uma lista de tipos de MIME que os APIs podem produce. O valor DEVE ser o descrito em [Tipos de Mime](#mime-types).                     |\n| param | Parâmetros que se separaram por espaços. `param name`,`param type`,`data type`,`is mandatory?`,`comment` `attribute(optional)` |\n| security | [Segurança](#security) para cada operação API.                                                                               |\n| success | resposta de sucesso que separou por espaços. `return code or default`,`{param type}`,`data type`,`comment` |.\n| failure | Resposta de falha que separou por espaços. `return code or default`,`{param type}`,`data type`,`comment` |\n| response | Igual ao `sucesso` e `falha` |\n| header | Cabeçalho em resposta que separou por espaços. `código de retorno`,`{tipo de parâmetro}`,`tipo de dados`,`comentário` |.\n| router | Definição do caminho que separou por espaços. caminho\",`path`,`[httpMethod]` |[httpMethod]` |\n| x-name | A chave de extensão, deve ser iniciada por x- e tomar apenas o valor json.                                                           |\n| x-codeSample | Optional Markdown use. tomar `file` como parâmetro. Isto irá então procurar um ficheiro nomeado como o resumo na pasta dada.                                      |\n| deprecated | Marcar o ponto final como depreciado.                                                                                               |\n\n## Mime Types\n\n`swag` aceita todos os tipos MIME que estão no formato correcto, ou seja, correspondem `*/*`.\nAlém disso, `swag` também aceita pseudónimos para alguns tipos de MIME, como se segue:\n\n\n| Alias                 | MIME Type                         |\n|-----------------------|-----------------------------------|\n| json                  | application/json                  |\n| xml                   | text/xml                          |\n| plain                 | text/plain                        |\n| html                  | text/html                         |\n| mpfd                  | multipart/form-data               |\n| x-www-form-urlencoded | application/x-www-form-urlencoded |\n| json-api              | application/vnd.api+json          |\n| json-stream           | application/x-json-stream         |\n| octet-stream          | application/octet-stream          |\n| png                   | image/png                         |\n| jpeg                  | image/jpeg                        |\n| gif                   | image/gif                         |\n| event-stream          | text/event-stream                 |\n\n\n\n## Tipo de parâmetro\n\n- query\n- path\n- header\n- body\n- formData\n\n## Tipo de dados\n\n- string (string)\n- integer (int, uint, uint32, uint64)\n- number (float32)\n- boolean (bool)\n- file (param data type when uploading)\n- user defined struct\n\n## Segurança\n| anotação | descrição | parâmetros | exemplo |\n|------------|-------------|------------|---------|\n| securitydefinitions.basic | [Basic](https://swagger.io/docs/specification/2-0/authentication/basic-authentication/) auth.  | | // @securityDefinitions.basicAuth | [Básico]()\n| securitydefinitions.apikey | [chave API](https://swagger.io/docs/specification/2-0/authentication/api-keys/) auth.            | in, name, description | // @securityDefinitions.apikey ApiKeyAuth |\n| securitydefinitions.oauth2.application | [Aplicação OAuth2](https://swagger.io/docs/specification/authentication/oauth2/) auth.       | tokenUrl, scope, description | // @securitydefinitions.oauth2.application OAuth2Application |\n| securitydefinitions.oauth2.implicit | [OAuth2 implicit](https://swagger.io/docs/specification/authentication/oauth2/) auth.          | authorizationUrl, scope, description | // @securitydefinitions.oauth2.implicit OAuth2Implicit | [OAuth2Implicit]()\n| securitydefinitions.oauth2.password | [OAuth2 password](https://swagger.io/docs/specification/authentication/oauth2/) auth.          | tokenUrl, scope, description | // @securitydefinitions.oauth2.password OAuth2Password |\n| securitydefinitions.oauth2.accessCode | [código de acesso OAuth2](https://swagger.io/docs/specification/authentication/oauth2/) auth.       | tokenUrl, authorizationUrl, scope, description | // @securitydefinitions.oauth2.accessCode OAuth2AccessCode | [código de acesso OAuth2.accessCode]()\n\n\n| anotação de parâmetros | exemplo |\n|---------------------------------|-------------------------------------------------------------------------|\n| in | // @in header |\n| name | // @name Authorization |\n| tokenUrl | // @tokenUrl https://example.com/oauth/token |\n| authorizationurl | // @authorizationurl https://example.com/oauth/authorize |\n| scope.hoge | // @scope.write Grants write access |\n| description | // @descrição OAuth protege os pontos finais da nossa entidade |\n\n## Atributo\n\n```go\n// @Param   enumstring  query     string     false  \"string enums\"       Enums(A, B, C)\n// @Param   enumint     query     int        false  \"int enums\"          Enums(1, 2, 3)\n// @Param   enumnumber  query     number     false  \"int enums\"          Enums(1.1, 1.2, 1.3)\n// @Param   string      query     string     false  \"string valid\"       minlength(5)  maxlength(10)\n// @Param   int         query     int        false  \"int valid\"          minimum(1)    maximum(10)\n// @Param   default     query     string     false  \"string default\"     default(A)\n// @Param   example     query     string     false  \"string example\"     example(string)\n// @Param   collection  query     []string   false  \"string collection\"  collectionFormat(multi)\n// @Param   extensions  query     []string   false  \"string collection\"  extensions(x-example=test,x-nullable)\n```\n\nIt also works for the struct fields:\n\n```go\ntype Foo struct {\n    Bar string `minLength:\"4\" maxLength:\"16\" example:\"random string\"`\n    Baz int `minimum:\"10\" maximum:\"20\" default:\"15\"`\n    Qux []string `enums:\"foo,bar,baz\"`\n}\n```\n\n### Disponível\n\nNome do campo | Tipo | Descrição\n---|:---:|---\n<a name=\"validate\"></a>validate | `string` | Determina a validação para o parâmetro. Os valores possíveis são: `required,optional`.\n<a name=\"parameterDefault\"></a>default | * | Declara o valor do parâmetro que o servidor utilizará se nenhum for fornecido, por exemplo, uma \"contagem\" para controlar o número de resultados por página poderá ser por defeito de 100 se não for fornecido pelo cliente no pedido. (Nota: \"por defeito\" não tem significado para os parâmetros requeridos).\nSee https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2. Ao contrário do esquema JSON, este valor DEVE estar em conformidade com o definido [`type`](#parameterType) para este parâmetro.\n<a name=\"parameterMaximum\"></a>maximum | `number` | Ver https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.2.\n<a name=\"parameterMinimum\"></a>minimum | `number` | Ver https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.3.\n<a name=\"parameterMultipleOf\"></a>multipleOf | `number` | Ver https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.1.\n<a name=\"parameterMaxLength\"></a>maxLength | `integer` | Ver https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.1.\n<a name=\"parameterMinLength\"></a>minLength | `integer` | Ver https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.2.\n<a name=\"parameterEnums\"></a>enums | [\\*] | Ver https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1.\n<a name=\"parameterFormat\"></a>format | `string` | O formato de extensão para o anteriormente mencionado [`type`](#parameterType). Ver [Data Type Formats](https://swagger.io/specification/v2/#dataTypeFormat) para mais detalhes.\n<a name=\"parameterCollectionFormat\"></a>collectionFormat | `string` |Determina o formato da matriz se for utilizada uma matriz de tipos. Os valores possíveis são: <ul><li>`csv` - valores separados por vírgulas `foo,bar`. <li>`ssv` - valores separados por espaço `foo bar`. <li>`tsv` - valores separados por tabulação `foo\\tbar`. <li>`pipes` - valores separados por tubo <code>foo&#124;bar</code>. <li>`multi` - corresponde a múltiplas instâncias de parâmetros em vez de múltiplos valores para uma única instância `foo=bar&foo=baz`. This is valid only for parameters [`in`](#parameterIn) \"query\" or \"formData\". </ul> Default value is `csv`.\n<a name=\"parameterExample\"></a>example | * | Declara o exemplo para o valor do parâmetro\n<a name=\"parameterExtensions\"></a>extensions | `string` | Acrescentar extensão aos parâmetros.\n\n### Futuro\n\nNome do campo | Tipo | Description\n---|:---:|---\n<a name=\"parameterPattern\"></a>pattern | `string` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.\n<a name=\"parameterMaxItems\"></a>maxItems | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.2.\n<a name=\"parameterMinItems\"></a>minItems | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.3.\n<a name=\"parameterUniqueItems\"></a>uniqueItems | `boolean` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.4.\n\n## Exemplos\n\n\n### Descrições em múltiplas linhas\n\nÉ possível acrescentar descrições que abranjam várias linhas tanto na descrição geral da api como em definições de rotas como esta:\n\n```go\n// @description This is the first line\n// @description This is the second line\n// @description And so forth.\n```\n\n### Estrutura definida pelo utilizador com um tipo de matriz\n\n```go\n// @Success 200 {array} model.Account <-- This is a user defined struct.\n```\n\n```go\npackage model\n\ntype Account struct {\n    ID   int    `json:\"id\" example:\"1\"`\n    Name string `json:\"name\" example:\"account name\"`\n}\n```\n\n\n### Declaração de estruturação de funções\n\nPode declarar as estruturas de resposta do seu pedido dentro de um corpo funcional.\nDeve ter de seguir a convenção de nomeação\n`<package-name>.<function-name>.<struct-name> `.\n\n```go\npackage main\n\n// @Param request body main.MyHandler.request true \"query params\"\n// @Success 200 {object} main.MyHandler.response\n// @Router /test [post]\nfunc MyHandler() {\n\ttype request struct {\n\t\tRequestField string\n\t}\n\n\ttype response struct {\n\t\tResponseField string\n\t}\n}\n```\n\n\n### Composição do modelo em resposta\n```go\n// JSONResult's data field will be overridden by the specific type proto.Order\n@success 200 {object} jsonresult.JSONResult{data=proto.Order} \"desc\"\n```\n\n```go\ntype JSONResult struct {\n    Code    int          `json:\"code\" `\n    Message string       `json:\"message\"`\n    Data    interface{}  `json:\"data\"`\n}\n\ntype Order struct { //in `proto` package\n    Id  uint            `json:\"id\"`\n    Data  interface{}   `json:\"data\"`\n}\n```\n\n- também suportam uma variedade de objectos e tipos primitivos como resposta aninhada\n```go\n@success 200 {object} jsonresult.JSONResult{data=[]proto.Order} \"desc\"\n@success 200 {object} jsonresult.JSONResult{data=string} \"desc\"\n@success 200 {object} jsonresult.JSONResult{data=[]string} \"desc\"\n```\n\n- campos múltiplos que se sobrepõem. campo será adicionado se não existir\n```go\n@success 200 {object} jsonresult.JSONResult{data1=string,data2=[]string,data3=proto.Order,data4=[]proto.Order} \"desc\"\n```\n- overriding deep-level fields\n```go\ntype DeepObject struct { //in `proto` package\n\t...\n}\n@success 200 {object} jsonresult.JSONResult{data1=proto.Order{data=proto.DeepObject},data2=[]proto.Order{data=[]proto.DeepObject}} \"desc\"\n```\n\n### Adicionar um cabeçalho em resposta\n\n```go\n// @Success      200              {string}  string    \"ok\"\n// @failure      400              {string}  string    \"error\"\n// @response     default          {string}  string    \"other error\"\n// @Header       200              {string}  Location  \"/entity/1\"\n// @Header       200,400,default  {string}  Token     \"token\"\n// @Header       all              {string}  Token2    \"token2\"\n```\n\n\n### Utilizar parâmetros de caminhos múltiplos\n\n```go\n/// ...\n// @Param group_id   path int true \"Group ID\"\n// @Param account_id path int true \"Account ID\"\n// ...\n// @Router /examples/groups/{group_id}/accounts/{account_id} [get]\n```\n\n### Adicionar múltiplos caminhos\n\n```go\n/// ...\n// @Param group_id path int true \"Group ID\"\n// @Param user_id  path int true \"User ID\"\n// ...\n// @Router /examples/groups/{group_id}/user/{user_id}/address [put]\n// @Router /examples/user/{user_id}/address [put]\n```\n\n### Exemplo de valor de estrutura\n\n```go\ntype Account struct {\n    ID   int    `json:\"id\" example:\"1\"`\n    Name string `json:\"name\" example:\"account name\"`\n    PhotoUrls []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n}\n```\n\n### Schema Exemplo do corpo\n\n```go\n// @Param email body string true \"message/rfc822\" SchemaExample(Subject: Testmail\\r\\n\\r\\nBody Message\\r\\n)\n```\n\n### Descrição da estrutura\n\n```go\n// Account model info\n// @Description User account information\n// @Description with user id and username\ntype Account struct {\n\t// ID this is userid\n\tID   int    `json:\"id\"`\n\tName string `json:\"name\"` // This is Name\n}\n```\n\n[#708](https://github.com/swaggo/swag/issues/708) O analisador trata apenas de comentários estruturais a partir de `@Description` attribute.\n\nAssim, gerou o doc. de swagger como se segue:\n```json\n\"Account\": {\n  \"type\":\"object\",\n  \"description\": \"User account information with user id and username\"\n  \"properties\": {\n    \"id\": {\n      \"type\": \"integer\",\n      \"description\": \"ID this is userid\"\n    },\n    \"name\": {\n      \"type\":\"string\",\n      \"description\": \"This is Name\"\n    }\n  }\n}\n```\n\n### Usar etiqueta do tipo swaggertype para suportar o tipo personalizado\n[#201](https://github.com/swaggo/swag/issues/201#issuecomment-475479409)\n\n```go\ntype TimestampTime struct {\n    time.Time\n}\n\n///implement encoding.JSON.Marshaler interface\nfunc (t *TimestampTime) MarshalJSON() ([]byte, error) {\n    bin := make([]byte, 16)\n    bin = strconv.AppendInt(bin[:0], t.Time.Unix(), 10)\n    return bin, nil\n}\n\nfunc (t *TimestampTime) UnmarshalJSON(bin []byte) error {\n    v, err := strconv.ParseInt(string(bin), 10, 64)\n    if err != nil {\n        return err\n    }\n    t.Time = time.Unix(v, 0)\n    return nil\n}\n///\n\ntype Account struct {\n    // Override primitive type by simply specifying it via `swaggertype` tag\n    ID     sql.NullInt64 `json:\"id\" swaggertype:\"integer\"`\n\n    // Override struct type to a primitive type 'integer' by specifying it via `swaggertype` tag\n    RegisterTime TimestampTime `json:\"register_time\" swaggertype:\"primitive,integer\"`\n\n    // Array types can be overridden using \"array,<prim_type>\" format\n    Coeffs []big.Float `json:\"coeffs\" swaggertype:\"array,number\"`\n}\n```\n\n[#379](https://github.com/swaggo/swag/issues/379)\n```go\ntype CerticateKeyPair struct {\n\tCrt []byte `json:\"crt\" swaggertype:\"string\" format:\"base64\" example:\"U3dhZ2dlciByb2Nrcw==\"`\n\tKey []byte `json:\"key\" swaggertype:\"string\" format:\"base64\" example:\"U3dhZ2dlciByb2Nrcw==\"`\n}\n```\ngenerated swagger doc as follows:\n```go\n\"api.MyBinding\": {\n  \"type\":\"object\",\n  \"properties\":{\n    \"crt\":{\n      \"type\":\"string\",\n      \"format\":\"base64\",\n      \"example\":\"U3dhZ2dlciByb2Nrcw==\"\n    },\n    \"key\":{\n      \"type\":\"string\",\n      \"format\":\"base64\",\n      \"example\":\"U3dhZ2dlciByb2Nrcw==\"\n    }\n  }\n}\n\n```\n\n### Utilizar anulações globais para suportar um tipo personalizado\n\nSe estiver a utilizar ficheiros gerados, as etiquetas [`swaggertype`](#use-swaggertype-tag-to-supported-custom-type) ou `swaggerignore` podem não ser possíveis.\n\nAo passar um mapeamento para swag com `--overridesFile` pode dizer swag para utilizar um tipo no lugar de outro onde quer que apareça. Por defeito, se um ficheiro `.swaggo` estiver presente no directório actual, será utilizado.\n\nGo code:\n```go\ntype MyStruct struct {\n  ID     sql.NullInt64 `json:\"id\"`\n  Name   sql.NullString `json:\"name\"`\n}\n```\n\n`.swaggo`:\n```\n// Substituir todos os NullInt64 por int\nreplace database/sql.NullInt64 int\n\n// Não inclua quaisquer campos do tipo base de database/sql.\nNullString no swagger docs\nskip    database/sql.NullString\n```\n\nAs directivas possíveis são comentários (começando por `//`), `replace path/to/a.type path/to/b.type`, e `skip path/to/a.type`.\n\n(Note que os caminhos completos para qualquer tipo nomeado devem ser fornecidos para evitar problemas quando vários pacotes definem um tipo com o mesmo nome)\n\nEntregue em:\n```go\n\"types.MyStruct\": {\n  \"id\": \"integer\"\n}\n\n### Use swaggerignore tag para excluir um campo\n\n```go\ntype Account struct {\n    ID   string    `json:\"id\"`\n    Name string     `json:\"name\"`\n    Ignored int     `swaggerignore:\"true\"`\n}\n```\n\n\n### Adicionar informações de extensão ao campo de estruturação\n\n```go\ntype Account struct {\n    ID   string    `json:\"id\"   extensions:\"x-nullable,x-abc=def,!x-omitempty\"` // extensions fields must start with \"x-\"\n}\n```\n\ngerar doc. de swagger como se segue:\n\n```go\n\"Account\": {\n    \"type\": \"object\",\n    \"properties\": {\n        \"id\": {\n            \"type\": \"string\",\n            \"x-nullable\": true,\n            \"x-abc\": \"def\",\n            \"x-omitempty\": false\n        }\n    }\n}\n```\n\n\n### Renomear modelo a expor\n\n```golang\ntype Resp struct {\n\tCode int\n}//@name Response\n```\n\n### Como utilizar as anotações de segurança\n\nInformações API gerais.\n\n```go\n// @securityDefinitions.basic BasicAuth\n\n// @securitydefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n```\n\nCada operação API.\n\n```go\n// @Security ApiKeyAuth\n```\n\nFaça-o OR condicione-o\n\n```go\n// @Security ApiKeyAuth\n// @Security OAuth2Application[write, admin]\n```\n\nFaça-o AND condição\n\n```go\n// @Security ApiKeyAuth && firebase\n// @Security OAuth2Application[write, admin] && APIKeyAuth\n```\n\n\n\n### Adicionar uma descrição para enumerar artigos\n\n```go\ntype Example struct {\n\t// Sort order:\n\t// * asc - Ascending, from A to Z.\n\t// * desc - Descending, from Z to A.\n\tOrder string `enums:\"asc,desc\"`\n}\n```\n\n### Gerar apenas tipos de ficheiros de documentos específicos\n\nPor defeito, o comando `swag` gera especificação Swagger em três tipos diferentes de ficheiros/arquivos:\n- docs.go\n- swagger.json\n- swagger.yaml\n\nSe desejar limitar um conjunto de tipos de ficheiros que devem ser gerados pode utilizar a bandeira `--outputTypes` (short `-ot`). O valor por defeito é `go,json,yaml` - tipos de saída separados por vírgula. Para limitar a saída apenas a ficheiros `go` e `yaml`, escrever-se-ia `go,yaml'. Com comando completo que seria `swag init --outputTypes go,yaml`.\n\n### Como usar tipos genéricos\n\n```go\n// @Success 200 {object} web.GenericNestedResponse[types.Post]\n// @Success 204 {object} web.GenericNestedResponse[types.Post, Types.AnotherOne]\n// @Success 201 {object} web.GenericNestedResponse[web.GenericInnerType[types.Post]]\nfunc GetPosts(w http.ResponseWriter, r *http.Request) {\n\t_ = web.GenericNestedResponse[types.Post]{}\n}\n```\nPara mais detalhes e outros exemplos, veja [esse arquivo](https://github.com/swaggo/swag/blob/master/testdata/generics_nested/api/api.go)\n\n### Alterar os delimitadores de acção padrão Go Template\n[#980](https://github.com/swaggo/swag/issues/980)\n[#1177](https://github.com/swaggo/swag/issues/1177)\n\nSe as suas anotações ou campos estruturantes contêm \"{{\" or \"}}\", a geração de modelos irá muito provavelmente falhar, uma vez que estes são os delimitadores por defeito para [go templates](https://pkg.go.dev/text/template#Template.Delims).\n\nPara que a geração funcione correctamente, pode alterar os delimitadores por defeito com `-td'. Por exemplo:\n``console\nswag init -g http/api.go -td \"[[,]\"\n```\n\nO novo delimitador é um fio com o formato \"`<left delimiter>`,`<right delimiter>`\".\n\n## Sobre o projecto\nEste projecto foi inspirado por [yvasiyarov/swagger](https://github.com/yvasiyarov/swagger) mas simplificámos a utilização e acrescentámos apoio a uma variedade de [frameworks web](#estruturas-web-suportadas). A fonte de imagem Gopher é [tenntenn/gopher-stickers](https://github.com/tenntenn/gopher-stickers). Tem licenças [creative commons licensing](http://creativecommons.org/licenses/by/3.0/deed.en).\n\n## Contribuidores\n\nEste projecto existe graças a todas as pessoas que contribuem. [[Contribute](CONTRIBUTING.md)].\n<a href=\"https://github.com/swaggo/swag/graphs/contributors\"><img src=\"https://opencollective.com/swag/contributors.svg?width=890&button=false\" /></a>\n\n\n## Apoios\n\nObrigado a todos os nossos apoiantes! 🙏 [[Become a backer](https://opencollective.com/swag#backer)]\n\n<a href=\"https://opencollective.com/swag#backers\" target=\"_blank\"><img src=\"https://opencollective.com/swag/backers.svg?width=890\"></a>\n\n\n## Patrocinadores\n\nApoiar este projecto tornando-se um patrocinador. O seu logótipo aparecerá aqui com um link para o seu website. [[Become a sponsor](https://opencollective.com/swag#sponsor)]\n\n\n<a href=\"https://opencollective.com/swag/sponsor/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/9/avatar.svg\"></a>\n\n\n## Licença\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fswaggo%2Fswag.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fswaggo%2Fswag?ref=badge_large)\n"
  },
  {
    "path": "README_zh-CN.md",
    "content": "# swag\n\n🌍 *[English](README.md) ∙ [简体中文](README_zh-CN.md)*\n\n<img align=\"right\" width=\"180px\" src=\"https://raw.githubusercontent.com/swaggo/swag/master/assets/swaggo.png\">\n\n[![Travis Status](https://img.shields.io/travis/swaggo/swag/master.svg)](https://travis-ci.org/swaggo/swag)\n[![Coverage Status](https://img.shields.io/codecov/c/github/swaggo/swag/master.svg)](https://codecov.io/gh/swaggo/swag)\n[![Go Report Card](https://goreportcard.com/badge/github.com/swaggo/swag)](https://goreportcard.com/report/github.com/swaggo/swag)\n[![codebeat badge](https://codebeat.co/badges/71e2f5e5-9e6b-405d-baf9-7cc8b5037330)](https://codebeat.co/projects/github-com-swaggo-swag-master)\n[![Go Doc](https://godoc.org/github.com/swaggo/swagg?status.svg)](https://godoc.org/github.com/swaggo/swag)\n[![Backers on Open Collective](https://opencollective.com/swag/backers/badge.svg)](#backers)\n[![Sponsors on Open Collective](https://opencollective.com/swag/sponsors/badge.svg)](#sponsors) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fswaggo%2Fswag.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fswaggo%2Fswag?ref=badge_shield)\n[![Release](https://img.shields.io/github/release/swaggo/swag.svg?style=flat-square)](https://github.com/swaggo/swag/releases)\n\nSwag将Go的注释转换为Swagger2.0文档。我们为流行的 [Go Web Framework](#支持的Web框架) 创建了各种插件，这样可以与现有Go项目快速集成（使用Swagger UI）。\n\n## 目录\n\n- [快速开始](#快速开始)\n- [支持的Web框架](#支持的web框架)\n- [如何与Gin集成](#如何与gin集成)\n- [格式化说明](#格式化说明)\n- [开发现状](#开发现状)\n- [声明式注释格式](#声明式注释格式)\n    - [通用API信息](#通用api信息)\n    - [API操作](#api操作)\n    - [安全性](#安全性)\n- [样例](#样例)\n    - [多行的描述](#多行的描述)\n    - [用户自定义的具有数组类型的结构](#用户自定义的具有数组类型的结构)\n    - [响应对象中的模型组合](#响应对象中的模型组合)\n    - [在响应中增加头字段](#在响应中增加头字段)\n    - [使用多路径参数](#使用多路径参数)\n    - [结构体的示例值](#结构体的示例值)\n    - [结构体描述](#结构体描述)\n    - [使用`swaggertype`标签更改字段类型](#使用`swaggertype`标签更改字段类型)\n    - [使用`swaggerignore`标签排除字段](#使用swaggerignore标签排除字段)\n    - [将扩展信息添加到结构字段](#将扩展信息添加到结构字段)\n    - [对展示的模型重命名](#对展示的模型重命名)\n    - [如何使用安全性注释](#如何使用安全性注释)\n- [项目相关](#项目相关)\n\n## 快速开始\n\n1. 将注释添加到API源代码中，请参阅声明性注释格式。\n2. 使用如下命令下载swag：\n\n```bash\ngo install github.com/swaggo/swag/cmd/swag@latest\n```\n\n从源码开始构建的话，需要有Go环境（1.19及以上版本）。\n\n或者从github的release页面下载预编译好的二进制文件。\n\n3. 在包含`main.go`文件的项目根目录运行`swag init`。这将会解析注释并生成需要的文件（`docs`文件夹和`docs/docs.go`）。\n\n```bash\nswag init\n```\n\n确保导入了生成的`docs/docs.go`文件，这样特定的配置文件才会被初始化。如果通用API注释没有写在`main.go`中，可以使用`-g`标识符来告知swag。\n\n```bash\nswag init -g http/api.go\n```\n\n4. (可选) 使用`fmt`格式化 SWAG 注释。(请先升级到最新版本)\n\n```bash\nswag fmt\n```\n\n## swag cli\n\n```bash\nswag init -h\nNAME:\n   swag init - Create docs.go\n\nUSAGE:\n   swag init [command options] [arguments...]\n\nOPTIONS:\n   --generalInfo value, -g value          API通用信息所在的go源文件路径，如果是相对路径则基于API解析目录 (默认: \"main.go\")\n   --dir value, -d value                  API解析目录 (默认: \"./\")\n   --exclude value                        解析扫描时排除的目录，多个目录可用逗号分隔（默认：空）\n   --propertyStrategy value, -p value     结构体字段命名规则，三种：snakecase,camelcase,pascalcase (默认: \"camelcase\")\n   --output value, -o value               文件(swagger.json, swagger.yaml and doc.go)输出目录 (默认: \"./docs\")\n   --parseVendor                          是否解析vendor目录里的go源文件，默认不\n   --parseDependency                      是否解析依赖目录中的go源文件，默认不\n   --parseDependencyLevel, --pdl          对'--parseDependency'参数进行增强, 是否解析依赖目录中的go源文件, 0 不解析, 1 只解析对象模型, 2 只解析API, 3 对象模型和API都解析 (default: 0)\n   --markdownFiles value, --md value      指定API的描述信息所使用的markdown文件所在的目录\n   --generatedTime                        是否输出时间到输出文件docs.go的顶部，默认是\n   --codeExampleFiles value, --cef value  解析包含用于 x-codeSamples 扩展的代码示例文件的文件夹，默认禁用\n   --parseInternal                        解析 internal 包中的go文件，默认禁用\n   --parseDepth value                     依赖解析深度 (默认: 100)\n   --instanceName value                   设置文档实例名 (默认: \"swagger\")\n```\n\n```bash\nswag fmt -h\nNAME:\n   swag fmt - format swag comments\n\nUSAGE:\n   swag fmt [command options] [arguments...]\n\nOPTIONS:\n   --dir value, -d value          API解析目录 (默认: \"./\")\n   --exclude value                解析扫描时排除的目录，多个目录可用逗号分隔（默认：空）\n   --generalInfo value, -g value  API通用信息所在的go源文件路径，如果是相对路径则基于API解析目录 (默认: \"main.go\")\n   --help, -h                     show help (default: false)\n\n```\n\n## 支持的Web框架\n\n- [gin](http://github.com/swaggo/gin-swagger)\n- [echo](http://github.com/swaggo/echo-swagger)\n- [buffalo](https://github.com/swaggo/buffalo-swagger)\n- [net/http](https://github.com/swaggo/http-swagger)\n- [gorilla/mux](https://github.com/swaggo/http-swagger)\n- [go-chi/chi](https://github.com/swaggo/http-swagger)\n- [flamingo](https://github.com/i-love-flamingo/swagger)\n- [fiber](https://github.com/gofiber/swagger)\n- [atreugo](https://github.com/Nerzal/atreugo-swagger)\n- [hertz](https://github.com/hertz-contrib/swagger)\n\n## 如何与Gin集成\n\n[点击此处](https://github.com/swaggo/swag/tree/master/example/celler)查看示例源代码。\n\n1. 使用`swag init`生成Swagger2.0文档后，导入如下代码包：\n\n```go\nimport \"github.com/swaggo/gin-swagger\" // gin-swagger middleware\nimport \"github.com/swaggo/files\" // swagger embed files\n```\n\n2. 在`main.go`源代码中添加通用的API注释：\n\n```go\n// @title           Swagger Example API\n// @version         1.0\n// @description     This is a sample server celler server.\n// @termsOfService  http://swagger.io/terms/\n\n// @contact.name   API Support\n// @contact.url    http://www.swagger.io/support\n// @contact.email  support@swagger.io\n\n// @license.name  Apache 2.0\n// @license.url   http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host      localhost:8080\n// @BasePath  /api/v1\n\n// @securityDefinitions.basic  BasicAuth\n\n// @externalDocs.description  OpenAPI\n// @externalDocs.url          https://swagger.io/resources/open-api/\nfunc main() {\n    r := gin.Default()\n\n    c := controller.NewController()\n\n    v1 := r.Group(\"/api/v1\")\n    {\n        accounts := v1.Group(\"/accounts\")\n        {\n            accounts.GET(\":id\", c.ShowAccount)\n            accounts.GET(\"\", c.ListAccounts)\n            accounts.POST(\"\", c.AddAccount)\n            accounts.DELETE(\":id\", c.DeleteAccount)\n            accounts.PATCH(\":id\", c.UpdateAccount)\n            accounts.POST(\":id/images\", c.UploadAccountImage)\n        }\n    //...\n    }\n    r.GET(\"/swagger/*any\", ginSwagger.WrapHandler(swaggerFiles.Handler))\n    r.Run(\":8080\")\n}\n//...\n```\n\n此外，可以动态设置一些通用的API信息。生成的代码包`docs`导出`SwaggerInfo`变量，使用该变量可以通过编码的方式设置标题、描述、版本、主机和基础路径。使用Gin的示例：\n\n```go\npackage main\n\nimport (\n    \"github.com/gin-gonic/gin\"\n    \"github.com/swaggo/files\"\n    \"github.com/swaggo/gin-swagger\"\n\n    \"./docs\" // docs is generated by Swag CLI, you have to import it.\n)\n\n// @contact.name   API Support\n// @contact.url    http://www.swagger.io/support\n// @contact.email  support@swagger.io\n\n// @license.name  Apache 2.0\n// @license.url   http://www.apache.org/licenses/LICENSE-2.0.html\nfunc main() {\n\n    // programatically set swagger info\n    docs.SwaggerInfo.Title = \"Swagger Example API\"\n    docs.SwaggerInfo.Description = \"This is a sample server Petstore server.\"\n    docs.SwaggerInfo.Version = \"1.0\"\n    docs.SwaggerInfo.Host = \"petstore.swagger.io\"\n    docs.SwaggerInfo.BasePath = \"/v2\"\n    docs.SwaggerInfo.Schemes = []string{\"http\", \"https\"}\n\n    r := gin.New()\n\n    // use ginSwagger middleware to serve the API docs\n    r.GET(\"/swagger/*any\", ginSwagger.WrapHandler(swaggerFiles.Handler))\n\n    r.Run()\n}\n```\n\n3. 在`controller`代码中添加API操作注释：\n\n```go\npackage controller\n\nimport (\n    \"fmt\"\n    \"net/http\"\n    \"strconv\"\n\n    \"github.com/gin-gonic/gin\"\n    \"github.com/swaggo/swag/example/celler/httputil\"\n    \"github.com/swaggo/swag/example/celler/model\"\n)\n\n// ShowAccount godoc\n// @Summary      Show an account\n// @Description  get string by ID\n// @Tags         accounts\n// @Accept       json\n// @Produce      json\n// @Param        id   path      int  true  \"Account ID\"\n// @Success      200  {object}  model.Account\n// @Failure      400  {object}  httputil.HTTPError\n// @Failure      404  {object}  httputil.HTTPError\n// @Failure      500  {object}  httputil.HTTPError\n// @Router       /accounts/{id} [get]\nfunc (c *Controller) ShowAccount(ctx *gin.Context) {\n  id := ctx.Param(\"id\")\n  aid, err := strconv.Atoi(id)\n  if err != nil {\n    httputil.NewError(ctx, http.StatusBadRequest, err)\n    return\n  }\n  account, err := model.AccountOne(aid)\n  if err != nil {\n    httputil.NewError(ctx, http.StatusNotFound, err)\n    return\n  }\n  ctx.JSON(http.StatusOK, account)\n}\n\n// ListAccounts godoc\n// @Summary      List accounts\n// @Description  get accounts\n// @Tags         accounts\n// @Accept       json\n// @Produce      json\n// @Param        q    query     string  false  \"name search by q\"  Format(email)\n// @Success      200  {array}   model.Account\n// @Failure      400  {object}  httputil.HTTPError\n// @Failure      404  {object}  httputil.HTTPError\n// @Failure      500  {object}  httputil.HTTPError\n// @Router       /accounts [get]\nfunc (c *Controller) ListAccounts(ctx *gin.Context) {\n  q := ctx.Request.URL.Query().Get(\"q\")\n  accounts, err := model.AccountsAll(q)\n  if err != nil {\n    httputil.NewError(ctx, http.StatusNotFound, err)\n    return\n  }\n  ctx.JSON(http.StatusOK, accounts)\n}\n//...\n```\n\n```bash\nswag init\n```\n\n4. 运行程序，然后在浏览器中访问 http://localhost:8080/swagger/index.html 。将看到Swagger 2.0 Api文档，如下所示：\n\n![swagger_index.html](https://raw.githubusercontent.com/swaggo/swag/master/assets/swagger-image.png)\n\n## 格式化说明\n\n可以针对Swag的注释自动格式化，就像`go fmt`。\n此处查看格式化结果 [here](https://github.com/swaggo/swag/tree/master/example/celler).\n\n示例：\n```shell\nswag fmt\n```\n\n排除目录（不扫描）示例：\n```shell\nswag fmt -d ./ --exclude ./internal\n```\n\n## 开发现状\n\n[Swagger 2.0 文档](https://swagger.io/docs/specification/2-0/basic-structure/)\n\n- [x] Basic Structure\n- [x] API Host and Base Path\n- [x] Paths and Operations\n- [x] Describing Parameters\n- [x] Describing Request Body\n- [x] Describing Responses\n- [x] MIME Types\n- [x] Authentication\n  - [x] Basic Authentication\n  - [x] API Keys\n- [x] Adding Examples\n- [x] File Upload\n- [x] Enums\n- [x] Grouping Operations With Tags\n- [ ] Swagger Extensions\n\n## 声明式注释格式\n\n## 通用API信息\n\n**示例** [`celler/main.go`](https://github.com/swaggo/swag/blob/master/example/celler/main.go)\n\n| 注释                    | 说明                                                                                            | 示例                                                            |\n| ----------------------- | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |\n| title                   | **必填** 应用程序的名称。                                                                       | // @title Swagger Example API                                   |\n| version                 | **必填** 提供应用程序API的版本。                                                                | // @version 1.0                                                 |\n| description             | 应用程序的简短描述。                                                                            | // @description This is a sample server celler server.          |\n| tag.name                | 标签的名称。                                                                                    | // @tag.name This is the name of the tag                        |\n| tag.description         | 标签的描述。                                                                                    | // @tag.description Cool Description                            |\n| tag.docs.url            | 标签的外部文档的URL。                                                                           | // @tag.docs.url https://example.com                            |\n| tag.docs.description    | 标签的外部文档说明。                                                                            | // @tag.docs.description Best example documentation             |\n| termsOfService          | API的服务条款。                                                                                 | // @termsOfService http://swagger.io/terms/                     |\n| contact.name            | 公开的API的联系信息。                                                                           | // @contact.name API Support                                    |\n| contact.url             | 联系信息的URL。 必须采用网址格式。                                                              | // @contact.url http://www.swagger.io/support                   |\n| contact.email           | 联系人/组织的电子邮件地址。 必须采用电子邮件地址的格式。                                        | // @contact.email support@swagger.io                            |\n| license.name            | **必填** 用于API的许可证名称。                                                                  | // @license.name Apache 2.0                                     |\n| license.url             | 用于API的许可证的URL。 必须采用网址格式。                                                       | // @license.url http://www.apache.org/licenses/LICENSE-2.0.html |\n| host                    | 运行API的主机（主机名或IP地址）。                                                               | // @host localhost:8080                                         |\n| BasePath                | 运行API的基本路径。                                                                             | // @BasePath /api/v1                                            |\n| accept                  | API 可以使用的 MIME 类型列表。 请注意，Accept 仅影响具有请求正文的操作，例如 POST、PUT 和 PATCH。 值必须如“[Mime类型](#mime类型)”中所述。                                  | // @accept json |\n| produce                 | API可以生成的MIME类型的列表。值必须如“[Mime类型](#mime类型)”中所述。                                  | // @produce json |\n| query.collection.format | 请求URI query里数组参数的默认格式：csv，multi，pipes，tsv，ssv。 如果未设置，则默认为csv。 | // @query.collection.format multi                               |\n| schemes                 | 用空格分隔的请求的传输协议。                                                                    | // @schemes http https                                          |\n| externalDocs.description | Description of the external document. | // @externalDocs.description OpenAPI |\n| externalDocs.url         | URL of the external document. | // @externalDocs.url https://swagger.io/resources/open-api/ |\n| x-name                  | 扩展的键必须以x-开头，并且只能使用json值                                                        | // @x-example-key {\"key\": \"value\"}                              |\n\n### 使用Markdown描述\n\n如果文档中的短字符串不足以完整表达，或者需要展示图片，代码示例等类似的内容，则可能需要使用Markdown描述。要使用Markdown描述，请使用一下注释。\n\n| 注释                     | 说明                                                                                 | 示例                                                                              |\n| ------------------------ | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------- |\n| title                    | **必填** 应用程序的名称。                                                            | // @title Swagger Example API                                                     |\n| version                  | **必填** 提供应用程序API的版本。                                                     | // @version 1.0                                                                   |\n| description.markdown     | 应用程序的简短描述。 从`api.md`文件中解析。 这是`@description`的替代用法。           | // @description.markdown No value needed, this parses the description from api.md |\n| tag.name                 | 标签的名称。                                                                         | // @tag.name This is the name of the tag                                          |\n| tag.description.markdown | 标签说明，这是`tag.description`的替代用法。 该描述将从名为`tagname.md的`文件中读取。 | // @tag.description.markdown                                                      |\n\n## API操作\n\nExample [celler/controller](https://github.com/swaggo/swag/tree/master/example/celler/controller)\n\n| 注释                   | 描述                                                                                             |\n|----------------------|------------------------------------------------------------------------------------------------|\n| description          | 操作行为的详细说明。                                                                                     |\n| description.markdown | 应用程序的简短描述。该描述将从名为`endpointname.md`的文件中读取。                                                      |\n| id                   | 用于标识操作的唯一字符串。在所有API操作中必须唯一。                                                                    |\n| tags                 | 每个API操作的标签列表，以逗号分隔。                                                                            |\n| summary              | 该操作的简短摘要。                                                                                      |\n| accept               | API 可以使用的 MIME 类型列表。 请注意，Accept 仅影响具有请求正文的操作，例如 POST、PUT 和 PATCH。 值必须如“[Mime类型](#mime类型)”中所述。  |\n| produce              | API可以生成的MIME类型的列表。值必须如“[Mime类型](#mime类型)”中所述。                                                  |\n| param                | 用空格分隔的参数。`param name`,`param type`,`data type`,`is mandatory?`,`comment` `attribute(optional)` |\n| security             | 每个API操作的[安全性](#安全性)。                                                                           |\n| success              | 以空格分隔的成功响应。`return code`,`{param type}`,`data type`,`comment`                                  |\n| failure              | 以空格分隔的故障响应。`return code`,`{param type}`,`data type`,`comment`                                  |\n| response             | 与success、failure作用相同                                                                           |\n| header               | 以空格分隔的头字段。 `return code`,`{param type}`,`data type`,`comment`                                  |\n| router               | 以空格分隔的路径定义。 `path`,`[httpMethod]`                                                              |\n| deprecatedrouter     | 与router相同，但是是deprecated的。                                                                      |\n| x-name               | 扩展字段必须以`x-`开头，并且只能使用json值。                                                                     |\n| deprecated           | 将当前API操作的所有路径设置为deprecated                                                                     |\n\n## Mime类型\n\n`swag` 接受所有格式正确的MIME类型, 即使匹配 `*/*`。除此之外，`swag`还接受某些MIME类型的别名，如下所示：\n\n| Alias                 | MIME Type                         |\n| --------------------- | --------------------------------- |\n| json                  | application/json                  |\n| xml                   | text/xml                          |\n| plain                 | text/plain                        |\n| html                  | text/html                         |\n| mpfd                  | multipart/form-data               |\n| x-www-form-urlencoded | application/x-www-form-urlencoded |\n| json-api              | application/vnd.api+json          |\n| json-stream           | application/x-json-stream         |\n| octet-stream          | application/octet-stream          |\n| png                   | image/png                         |\n| jpeg                  | image/jpeg                        |\n| gif                   | image/gif                         |\n| event-stream          | text/event-stream                 |\n\n## 参数类型\n\n- query\n- path\n- header\n- body\n- formData\n\n## 数据类型\n\n- string (string)\n- integer (int, uint, uint32, uint64)\n- number (float32)\n- boolean (bool)\n- user defined struct\n\n## 安全性\n\n| 注释                                   | 描述                                                                                          | 参数                              | 示例                                                         |\n| -------------------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------ |\n| securitydefinitions.basic              | [Basic](https://swagger.io/docs/specification/2-0/authentication/basic-authentication/) auth. |                                   | // @securityDefinitions.basic BasicAuth                      |\n| securitydefinitions.apikey             | [API key](https://swagger.io/docs/specification/2-0/authentication/api-keys/) auth.           | in, name                          | // @securityDefinitions.apikey ApiKeyAuth                    |\n| securitydefinitions.oauth2.application | [OAuth2 application](https://swagger.io/docs/specification/authentication/oauth2/) auth.      | tokenUrl, scope                   | // @securitydefinitions.oauth2.application OAuth2Application |\n| securitydefinitions.oauth2.implicit    | [OAuth2 implicit](https://swagger.io/docs/specification/authentication/oauth2/) auth.         | authorizationUrl, scope           | // @securitydefinitions.oauth2.implicit OAuth2Implicit       |\n| securitydefinitions.oauth2.password    | [OAuth2 password](https://swagger.io/docs/specification/authentication/oauth2/) auth.         | tokenUrl, scope                   | // @securitydefinitions.oauth2.password OAuth2Password       |\n| securitydefinitions.oauth2.accessCode  | [OAuth2 access code](https://swagger.io/docs/specification/authentication/oauth2/) auth.      | tokenUrl, authorizationUrl, scope | // @securitydefinitions.oauth2.accessCode OAuth2AccessCode   |\n\n| 参数注释         | 示例                                                     |\n| ---------------- | -------------------------------------------------------- |\n| in               | // @in header                                            |\n| name             | // @name Authorization                                   |\n| tokenUrl         | // @tokenUrl https://example.com/oauth/token             |\n| authorizationurl | // @authorizationurl https://example.com/oauth/authorize |\n| scope.hoge       | // @scope.write Grants write access                      |\n\n## 属性\n\n```go\n// @Param   enumstring  query     string     false  \"string enums\"       Enums(A, B, C)\n// @Param   enumint     query     int        false  \"int enums\"          Enums(1, 2, 3)\n// @Param   enumnumber  query     number     false  \"int enums\"          Enums(1.1, 1.2, 1.3)\n// @Param   string      query     string     false  \"string valid\"       minlength(5)  maxlength(10)\n// @Param   int         query     int        false  \"int valid\"          minimum(1)    maximum(10)\n// @Param   default     query     string     false  \"string default\"     default(A)\n// @Param   collection  query     []string   false  \"string collection\"  collectionFormat(multi)\n// @Param   extensions  query     []string   false  \"string collection\"  extensions(x-example=test,x-nullable)\n```\n\n也适用于结构体字段：\n\n```go\ntype Foo struct {\n    Bar string `minLength:\"4\" maxLength:\"16\"`\n    Baz int `minimum:\"10\" maximum:\"20\" default:\"15\"`\n    Qux []string `enums:\"foo,bar,baz\"`\n}\n```\n\n### 当前可用的\n\n| 字段名           | 类型      | 描述                                                                                                                                                                                                                                                                                                                                                                  |\n| ---------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| default          | *         | 声明如果未提供任何参数，则服务器将使用的默认参数值，例如，如果请求中的客户端未提供该参数，则用于控制每页结果数的“计数”可能默认为100。 （注意：“default”对于必需的参数没有意义）。参看 https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2。 与JSON模式不同，此值务必符合此参数的定义[类型](#parameterType)。                                  |\n| maximum          | `number`  | 参看 https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.2.                                                                                                                                                                                                                                                                                   |\n| minimum          | `number`  | 参看 https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.3.                                                                                                                                                                                                                                                                                   |\n| maxLength        | `integer` | 参看 https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.1.                                                                                                                                                                                                                                                                                   |\n| minLength        | `integer` | 参看 https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.2.                                                                                                                                                                                                                                                                                   |\n| enums            | [\\*]      | 参看 https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1.                                                                                                                                                                                                                                                                                   |\n| format           | `string`  | 上面提到的[类型](#parameterType)的扩展格式。有关更多详细信息，请参见[数据类型格式](https://swagger.io/specification/v2/#dataTypeFormat)。                                                                                                                                                                                                                             |\n| collectionFormat | `string`  | 指定query数组参数的格式。 可能的值为： <ul><li>`csv` - 逗号分隔值 `foo,bar`. <li>`ssv` - 空格分隔值 `foo bar`. <li>`tsv` - 制表符分隔值 `foo\\tbar`. <li>`pipes` - 管道符分隔值 <code>foo&#124;bar</code>. <li>`multi` - 对应于多个参数实例，而不是单个实例 `foo=bar＆foo=baz` 的多个值。这仅对“`query`”或“`formData`”中的参数有效。 </ul> 默认值是 `csv`。 |\n\n### 进一步的\n\n| 字段名      |   类型    | 描述                                                                               |\n| ----------- | :-------: | ---------------------------------------------------------------------------------- |\n| multipleOf  | `number`  | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.1. |\n| pattern     | `string`  | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3. |\n| maxItems    | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.2. |\n| minItems    | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.3. |\n| uniqueItems | `boolean` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.4. |\n\n## 样例\n\n### 多行的描述\n\n可以在常规api描述或路由定义中添加跨越多行的描述，如下所示：\n\n```go\n// @description This is the first line\n// @description This is the second line\n// @description And so forth.\n```\n\n### 用户自定义的具有数组类型的结构\n\n```go\n// @Success 200 {array} model.Account <-- This is a user defined struct.\n```\n\n```go\npackage model\n\ntype Account struct {\n    ID   int    `json:\"id\" example:\"1\"`\n    Name string `json:\"name\" example:\"account name\"`\n}\n```\n\n### 响应对象中的模型组合\n\n```go\n// JSONResult的data字段类型将被proto.Order类型替换\n@success 200 {object} jsonresult.JSONResult{data=proto.Order} \"desc\"\n```\n\n```go\ntype JSONResult struct {\n    Code    int          `json:\"code\" `\n    Message string       `json:\"message\"`\n    Data    interface{}  `json:\"data\"`\n}\n\ntype Order struct { //in `proto` package\n    ...\n}\n```\n\n- 还支持对象数组和原始类型作为嵌套响应\n\n```go\n@success 200 {object} jsonresult.JSONResult{data=[]proto.Order} \"desc\"\n@success 200 {object} jsonresult.JSONResult{data=string} \"desc\"\n@success 200 {object} jsonresult.JSONResult{data=[]string} \"desc\"\n```\n\n- 替换多个字段的类型。如果某字段不存在，将添加该字段。\n\n```go\n@success 200 {object} jsonresult.JSONResult{data1=string,data2=[]string,data3=proto.Order,data4=[]proto.Order} \"desc\"\n```\n\n### 在响应中增加头字段\n\n```go\n// @Success      200              {string}  string    \"ok\"\n// @failure      400              {string}  string    \"error\"\n// @response     default          {string}  string    \"other error\"\n// @Header       200              {string}  Location  \"/entity/1\"\n// @Header       200,400,default  {string}  Token     \"token\"\n// @Header       all              {string}  Token2    \"token2\"\n```\n\n### 使用多路径参数\n\n```go\n/// ...\n// @Param  group_id    path  int  true  \"Group ID\"\n// @Param  account_id  path  int  true  \"Account ID\"\n// ...\n// @Router /examples/groups/{group_id}/accounts/{account_id} [get]\n```\n\n### 结构体的示例值\n\n```go\ntype Account struct {\n    ID   int    `json:\"id\" example:\"1\"`\n    Name string `json:\"name\" example:\"account name\"`\n    PhotoUrls []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n}\n```\n\n### 结构体描述\n\n```go\ntype Account struct {\n    // ID this is userid\n    ID   int    `json:\"id\"`\n    Name string `json:\"name\"` // This is Name\n}\n```\n\n### 使用`swaggertype`标签更改字段类型\n\n[#201](https://github.com/swaggo/swag/issues/201#issuecomment-475479409)\n\n```go\ntype TimestampTime struct {\n    time.Time\n}\n\n///实现encoding.JSON.Marshaler接口\nfunc (t *TimestampTime) MarshalJSON() ([]byte, error) {\n    bin := make([]byte, 16)\n    bin = strconv.AppendInt(bin[:0], t.Time.Unix(), 10)\n    return bin, nil\n}\n\n///实现encoding.JSON.Unmarshaler接口\nfunc (t *TimestampTime) UnmarshalJSON(bin []byte) error {\n    v, err := strconv.ParseInt(string(bin), 10, 64)\n    if err != nil {\n        return err\n    }\n    t.Time = time.Unix(v, 0)\n    return nil\n}\n///\n\ntype Account struct {\n    // 使用`swaggertype`标签将别名类型更改为内置类型integer\n    ID     sql.NullInt64 `json:\"id\" swaggertype:\"integer\"`\n\n    // 使用`swaggertype`标签更改struct类型为内置类型integer\n    RegisterTime TimestampTime `json:\"register_time\" swaggertype:\"primitive,integer\"`\n\n    // Array types can be overridden using \"array,<prim_type>\" format\n    Coeffs []big.Float `json:\"coeffs\" swaggertype:\"array,number\"`\n}\n```\n\n[#379](https://github.com/swaggo/swag/issues/379)\n\n```go\ntype CerticateKeyPair struct {\n    Crt []byte `json:\"crt\" swaggertype:\"string\" format:\"base64\" example:\"U3dhZ2dlciByb2Nrcw==\"`\n    Key []byte `json:\"key\" swaggertype:\"string\" format:\"base64\" example:\"U3dhZ2dlciByb2Nrcw==\"`\n}\n```\n\n生成的swagger文档如下：\n\n```go\n\"api.MyBinding\": {\n  \"type\":\"object\",\n  \"properties\":{\n    \"crt\":{\n      \"type\":\"string\",\n      \"format\":\"base64\",\n      \"example\":\"U3dhZ2dlciByb2Nrcw==\"\n    },\n    \"key\":{\n      \"type\":\"string\",\n      \"format\":\"base64\",\n      \"example\":\"U3dhZ2dlciByb2Nrcw==\"\n    }\n  }\n}\n```\n\n### 使用`swaggerignore`标签排除字段\n\n```go\ntype Account struct {\n    ID   string    `json:\"id\"`\n    Name string     `json:\"name\"`\n    Ignored int     `swaggerignore:\"true\"`\n}\n```\n\n### 将扩展信息添加到结构字段\n\n```go\ntype Account struct {\n    ID   string    `json:\"id\"   extensions:\"x-nullable,x-abc=def,!x-omitempty\"` // 扩展字段必须以\"x-\"开头\n}\n```\n\n生成swagger文档，如下所示：\n\n```go\n\"Account\": {\n    \"type\": \"object\",\n    \"properties\": {\n        \"id\": {\n            \"type\": \"string\",\n            \"x-nullable\": true,\n            \"x-abc\": \"def\",\n            \"x-omitempty\": false\n        }\n    }\n}\n```\n\n### 对展示的模型重命名\n\n```go\ntype Resp struct {\n    Code int\n}//@name Response\n```\n\n### 如何使用安全性注释\n\n通用API信息。\n\n```go\n// @securityDefinitions.basic BasicAuth\n\n// @securitydefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n```\n\n每个API操作。\n\n```go\n// @Security ApiKeyAuth\n```\n\n使用AND条件。\n\n```go\n// @Security ApiKeyAuth && OAuth2Application[write, admin]\n```\n\n## 项目相关\n\nThis 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).\n\n## 贡献者\n\nThis project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].\n<a href=\"https://github.com/swaggo/swag/graphs/contributors\"><img src=\"https://opencollective.com/swag/contributors.svg?width=890&button=false\" /></a>\n\n## 支持者\n\nThank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/swag#backer)]\n\n<a href=\"https://opencollective.com/swag#backers\" target=\"_blank\"><img src=\"https://opencollective.com/swag/backers.svg?width=890\"></a>\n\n## 赞助商\n\nSupport 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)]\n\n<a href=\"https://opencollective.com/swag/sponsor/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/swag/sponsor/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/swag/sponsor/9/avatar.svg\"></a>\n\n## License\n\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fswaggo%2Fswag.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fswaggo%2Fswag?ref=badge_large)\n"
  },
  {
    "path": "cmd/swag/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/urfave/cli/v2\"\n\n\t\"github.com/swaggo/swag\"\n\t\"github.com/swaggo/swag/format\"\n\t\"github.com/swaggo/swag/gen\"\n)\n\nconst (\n\tsearchDirFlag            = \"dir\"\n\texcludeFlag              = \"exclude\"\n\tgeneralInfoFlag          = \"generalInfo\"\n\tpipeFlag                 = \"pipe\"\n\tpropertyStrategyFlag     = \"propertyStrategy\"\n\toutputFlag               = \"output\"\n\toutputTypesFlag          = \"outputTypes\"\n\tparseVendorFlag          = \"parseVendor\"\n\tparseDependencyFlag      = \"parseDependency\"\n\tuseStructNameFlag        = \"useStructName\"\n\tparseDependencyLevelFlag = \"parseDependencyLevel\"\n\tmarkdownFilesFlag        = \"markdownFiles\"\n\tcodeExampleFilesFlag     = \"codeExampleFiles\"\n\tparseInternalFlag        = \"parseInternal\"\n\tgeneratedTimeFlag        = \"generatedTime\"\n\trequiredByDefaultFlag    = \"requiredByDefault\"\n\tparseDepthFlag           = \"parseDepth\"\n\tinstanceNameFlag         = \"instanceName\"\n\toverridesFileFlag        = \"overridesFile\"\n\tparseGoListFlag          = \"parseGoList\"\n\tquietFlag                = \"quiet\"\n\ttagsFlag                 = \"tags\"\n\tparseExtensionFlag       = \"parseExtension\"\n\ttemplateDelimsFlag       = \"templateDelims\"\n\tpackageName              = \"packageName\"\n\tcollectionFormatFlag     = \"collectionFormat\"\n\tpackagePrefixFlag        = \"packagePrefix\"\n\tstateFlag                = \"state\"\n\tparseFuncBodyFlag        = \"parseFuncBody\"\n\tparseGoPackagesFlag      = \"parseGoPackages\"\n)\n\nvar initFlags = []cli.Flag{\n\t&cli.BoolFlag{\n\t\tName:    quietFlag,\n\t\tAliases: []string{\"q\"},\n\t\tUsage:   \"Make the logger quiet.\",\n\t},\n\t&cli.StringFlag{\n\t\tName:    generalInfoFlag,\n\t\tAliases: []string{\"g\"},\n\t\tValue:   \"main.go\",\n\t\tUsage:   \"Go file path in which 'swagger general API Info' is written\",\n\t},\n\t&cli.StringFlag{\n\t\tName:    searchDirFlag,\n\t\tAliases: []string{\"d\"},\n\t\tValue:   \"./\",\n\t\tUsage:   \"Directories you want to parse,comma separated and general-info file must be in the first one\",\n\t},\n\t&cli.StringFlag{\n\t\tName:  excludeFlag,\n\t\tUsage: \"Exclude directories and files when searching, comma separated\",\n\t},\n\t&cli.StringFlag{\n\t\tName:    propertyStrategyFlag,\n\t\tAliases: []string{\"p\"},\n\t\tValue:   swag.CamelCase,\n\t\tUsage:   \"Property Naming Strategy like \" + swag.SnakeCase + \",\" + swag.CamelCase + \",\" + swag.PascalCase,\n\t},\n\t&cli.StringFlag{\n\t\tName:    outputFlag,\n\t\tAliases: []string{\"o\"},\n\t\tValue:   \"./docs\",\n\t\tUsage:   \"Output directory for all the generated files(swagger.json, swagger.yaml and docs.go)\",\n\t},\n\t&cli.StringFlag{\n\t\tName:    outputTypesFlag,\n\t\tAliases: []string{\"ot\"},\n\t\tValue:   \"go,json,yaml\",\n\t\tUsage:   \"Output types of generated files (docs.go, swagger.json, swagger.yaml) like go,json,yaml\",\n\t},\n\t&cli.BoolFlag{\n\t\tName:  parseVendorFlag,\n\t\tUsage: \"Parse go files in 'vendor' folder, disabled by default\",\n\t},\n\t&cli.IntFlag{\n\t\tName:    parseDependencyLevelFlag,\n\t\tAliases: []string{\"pdl\"},\n\t\tUsage:   \"Parse go files inside dependency folder, 0 disabled, 1 only parse models, 2 only parse operations, 3 parse all\",\n\t},\n\t&cli.BoolFlag{\n\t\tName:    parseDependencyFlag,\n\t\tAliases: []string{\"pd\"},\n\t\tUsage:   \"Parse go files inside dependency folder, disabled by default\",\n\t},\n\t&cli.BoolFlag{\n\t\tName:    useStructNameFlag,\n\t\tAliases: []string{\"st\"},\n\t\tUsage:   \"Dont use those ugly full-path names when using dependency flag\",\n\t},\n\t&cli.StringFlag{\n\t\tName:    markdownFilesFlag,\n\t\tAliases: []string{\"md\"},\n\t\tValue:   \"\",\n\t\tUsage:   \"Parse folder containing markdown files to use as description, disabled by default\",\n\t},\n\t&cli.StringFlag{\n\t\tName:    codeExampleFilesFlag,\n\t\tAliases: []string{\"cef\"},\n\t\tValue:   \"\",\n\t\tUsage:   \"Parse folder containing code example files to use for the x-codeSamples extension, disabled by default\",\n\t},\n\t&cli.BoolFlag{\n\t\tName:  parseInternalFlag,\n\t\tUsage: \"Parse go files in internal packages, disabled by default\",\n\t},\n\t&cli.BoolFlag{\n\t\tName:  generatedTimeFlag,\n\t\tUsage: \"Generate timestamp at the top of docs.go, disabled by default\",\n\t},\n\t&cli.IntFlag{\n\t\tName:  parseDepthFlag,\n\t\tValue: 100,\n\t\tUsage: \"Dependency parse depth\",\n\t},\n\t&cli.BoolFlag{\n\t\tName:  requiredByDefaultFlag,\n\t\tUsage: \"Set validation required for all fields by default\",\n\t},\n\t&cli.StringFlag{\n\t\tName:  instanceNameFlag,\n\t\tValue: \"\",\n\t\tUsage: \"This parameter can be used to name different swagger document instances. It is optional.\",\n\t},\n\t&cli.StringFlag{\n\t\tName:  overridesFileFlag,\n\t\tValue: gen.DefaultOverridesFile,\n\t\tUsage: \"File to read global type overrides from.\",\n\t},\n\t&cli.BoolFlag{\n\t\tName:  parseGoListFlag,\n\t\tValue: true,\n\t\tUsage: \"Parse dependency via 'go list'\",\n\t},\n\t&cli.StringFlag{\n\t\tName:  parseExtensionFlag,\n\t\tValue: \"\",\n\t\tUsage: \"Parse only those operations that match given extension\",\n\t},\n\t&cli.StringFlag{\n\t\tName:    tagsFlag,\n\t\tAliases: []string{\"t\"},\n\t\tValue:   \"\",\n\t\tUsage:   \"A comma-separated list of tags to filter the APIs for which the documentation is generated.Special case if the tag is prefixed with the '!' character then the APIs with that tag will be excluded\",\n\t},\n\t&cli.StringFlag{\n\t\tName:    templateDelimsFlag,\n\t\tAliases: []string{\"td\"},\n\t\tValue:   \"\",\n\t\tUsage:   \"Provide custom delimiters for Go template generation. The format is leftDelim,rightDelim. For example: \\\"[[,]]\\\"\",\n\t},\n\t&cli.StringFlag{\n\t\tName:  packageName,\n\t\tValue: \"\",\n\t\tUsage: \"A package name of docs.go, using output directory name by default (check `--output` option)\",\n\t},\n\t&cli.StringFlag{\n\t\tName:    collectionFormatFlag,\n\t\tAliases: []string{\"cf\"},\n\t\tValue:   \"csv\",\n\t\tUsage:   \"Set default collection format\",\n\t},\n\t&cli.StringFlag{\n\t\tName:  packagePrefixFlag,\n\t\tValue: \"\",\n\t\tUsage: \"Parse only packages whose import path match the given prefix, comma separated\",\n\t},\n\t&cli.StringFlag{\n\t\tName:  stateFlag,\n\t\tValue: \"\",\n\t\tUsage: \"Set host state for swagger.json\",\n\t},\n\t&cli.BoolFlag{\n\t\tName:  parseFuncBodyFlag,\n\t\tUsage: \"Parse API info within body of functions in go files, disabled by default\",\n\t},\n\t&cli.BoolFlag{\n\t\tName:  parseGoPackagesFlag,\n\t\tUsage: \"Parse Go sources by golang.org/x/tools/go/packages, disabled by default\",\n\t},\n}\n\nfunc initAction(ctx *cli.Context) error {\n\tstrategy := ctx.String(propertyStrategyFlag)\n\n\tswitch strategy {\n\tcase swag.CamelCase, swag.SnakeCase, swag.PascalCase:\n\tdefault:\n\t\treturn fmt.Errorf(\"not supported %s propertyStrategy\", strategy)\n\t}\n\n\tleftDelim, rightDelim := \"{{\", \"}}\"\n\n\tif ctx.IsSet(templateDelimsFlag) {\n\t\tdelims := strings.Split(ctx.String(templateDelimsFlag), \",\")\n\t\tif len(delims) != 2 {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"exactly two template delimiters must be provided, comma separated\",\n\t\t\t)\n\t\t} else if delims[0] == delims[1] {\n\t\t\treturn fmt.Errorf(\"template delimiters must be different\")\n\t\t}\n\t\tleftDelim, rightDelim = strings.TrimSpace(\n\t\t\tdelims[0],\n\t\t), strings.TrimSpace(\n\t\t\tdelims[1],\n\t\t)\n\t}\n\n\toutputTypes := strings.Split(ctx.String(outputTypesFlag), \",\")\n\tif len(outputTypes) == 0 {\n\t\treturn fmt.Errorf(\"no output types specified\")\n\t}\n\tlogger := log.New(os.Stdout, \"\", log.LstdFlags)\n\tif ctx.Bool(quietFlag) {\n\t\tlogger = log.New(io.Discard, \"\", log.LstdFlags)\n\t}\n\n\tcollectionFormat := swag.TransToValidCollectionFormat(\n\t\tctx.String(collectionFormatFlag),\n\t)\n\tif collectionFormat == \"\" {\n\t\treturn fmt.Errorf(\n\t\t\t\"not supported %s collectionFormat\",\n\t\t\tctx.String(collectionFormat),\n\t\t)\n\t}\n\n\tvar pdv = ctx.Int(parseDependencyLevelFlag)\n\tif pdv == 0 {\n\t\tif ctx.Bool(parseDependencyFlag) {\n\t\t\tpdv = 1\n\t\t}\n\t}\n\treturn gen.New().Build(&gen.Config{\n\t\tSearchDir:           ctx.String(searchDirFlag),\n\t\tExcludes:            ctx.String(excludeFlag),\n\t\tParseExtension:      ctx.String(parseExtensionFlag),\n\t\tMainAPIFile:         ctx.String(generalInfoFlag),\n\t\tPropNamingStrategy:  strategy,\n\t\tOutputDir:           ctx.String(outputFlag),\n\t\tOutputTypes:         outputTypes,\n\t\tParseVendor:         ctx.Bool(parseVendorFlag),\n\t\tParseDependency:     pdv,\n\t\tMarkdownFilesDir:    ctx.String(markdownFilesFlag),\n\t\tParseInternal:       ctx.Bool(parseInternalFlag),\n\t\tUseStructNames:      ctx.Bool(useStructNameFlag),\n\t\tGeneratedTime:       ctx.Bool(generatedTimeFlag),\n\t\tRequiredByDefault:   ctx.Bool(requiredByDefaultFlag),\n\t\tCodeExampleFilesDir: ctx.String(codeExampleFilesFlag),\n\t\tParseDepth:          ctx.Int(parseDepthFlag),\n\t\tInstanceName:        ctx.String(instanceNameFlag),\n\t\tOverridesFile:       ctx.String(overridesFileFlag),\n\t\tParseGoList:         ctx.Bool(parseGoListFlag),\n\t\tTags:                ctx.String(tagsFlag),\n\t\tLeftTemplateDelim:   leftDelim,\n\t\tRightTemplateDelim:  rightDelim,\n\t\tPackageName:         ctx.String(packageName),\n\t\tDebugger:            logger,\n\t\tCollectionFormat:    collectionFormat,\n\t\tPackagePrefix:       ctx.String(packagePrefixFlag),\n\t\tState:               ctx.String(stateFlag),\n\t\tParseFuncBody:       ctx.Bool(parseFuncBodyFlag),\n\t\tParseGoPackages:     ctx.Bool(parseGoPackagesFlag),\n\t})\n}\n\nfunc main() {\n\tapp := cli.NewApp()\n\tapp.Version = swag.Version\n\tapp.Usage = \"Automatically generate RESTful API documentation with Swagger 2.0 for Go.\"\n\tapp.Commands = []*cli.Command{\n\t\t{\n\t\t\tName:    \"init\",\n\t\t\tAliases: []string{\"i\"},\n\t\t\tUsage:   \"Create docs.go\",\n\t\t\tAction:  initAction,\n\t\t\tFlags:   initFlags,\n\t\t},\n\t\t{\n\t\t\tName:    \"fmt\",\n\t\t\tAliases: []string{\"f\"},\n\t\t\tUsage:   \"format swag comments\",\n\t\t\tAction: func(c *cli.Context) error {\n\n\t\t\t\tif c.Bool(pipeFlag) {\n\t\t\t\t\treturn format.New().Run(os.Stdin, os.Stdout)\n\t\t\t\t}\n\n\t\t\t\tsearchDir := c.String(searchDirFlag)\n\t\t\t\texcludeDir := c.String(excludeFlag)\n\t\t\t\tmainFile := c.String(generalInfoFlag)\n\n\t\t\t\treturn format.New().Build(&format.Config{\n\t\t\t\t\tSearchDir: searchDir,\n\t\t\t\t\tExcludes:  excludeDir,\n\t\t\t\t\tMainFile:  mainFile,\n\t\t\t\t})\n\t\t\t},\n\t\t\tFlags: []cli.Flag{\n\t\t\t\t&cli.StringFlag{\n\t\t\t\t\tName:    searchDirFlag,\n\t\t\t\t\tAliases: []string{\"d\"},\n\t\t\t\t\tValue:   \"./\",\n\t\t\t\t\tUsage:   \"Directories you want to parse,comma separated and general-info file must be in the first one\",\n\t\t\t\t},\n\t\t\t\t&cli.StringFlag{\n\t\t\t\t\tName:  excludeFlag,\n\t\t\t\t\tUsage: \"Exclude directories and files when searching, comma separated\",\n\t\t\t\t},\n\t\t\t\t&cli.StringFlag{\n\t\t\t\t\tName:    generalInfoFlag,\n\t\t\t\t\tAliases: []string{\"g\"},\n\t\t\t\t\tValue:   \"main.go\",\n\t\t\t\t\tUsage:   \"Go file path in which 'swagger general API Info' is written\",\n\t\t\t\t},\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:    \"pipe\",\n\t\t\t\t\tAliases: []string{\"p\"},\n\t\t\t\t\tValue:   false,\n\t\t\t\t\tUsage:   \"Read from stdin, write to stdout.\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "const.go",
    "content": "package swag\n\nimport (\n\t\"go/ast\"\n\t\"go/token\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode/utf8\"\n)\n\n// ConstVariable a model to record a const variable\ntype ConstVariable struct {\n\tName    *ast.Ident\n\tType    ast.Expr\n\tValue   any\n\tComment string\n\tFile    *ast.File\n\tPkg     *PackageDefinitions\n}\n\n// VariableName gets the name for this const variable, taking into account comment overrides.\nfunc (cv *ConstVariable) VariableName() string {\n\tif ignoreNameOverride(cv.Name.Name) {\n\t\treturn cv.Name.Name[1:]\n\t}\n\n\tif overriddenName := cv.nameOverride(); overriddenName != \"\" {\n\t\treturn overriddenName\n\t}\n\n\treturn cv.Name.Name\n}\n\nfunc (cv *ConstVariable) nameOverride() string {\n\tif len(cv.Comment) == 0 {\n\t\treturn \"\"\n\t}\n\n\tcomment := strings.TrimSpace(strings.TrimLeft(cv.Comment, \"/\"))\n\ttexts := overrideNameRegex.FindStringSubmatch(comment)\n\tif len(texts) > 1 {\n\t\treturn texts[1]\n\t}\n\treturn \"\"\n}\n\nvar escapedChars = map[uint8]uint8{\n\t'n':  '\\n',\n\t'r':  '\\r',\n\t't':  '\\t',\n\t'v':  '\\v',\n\t'\\\\': '\\\\',\n\t'\"':  '\"',\n}\n\n// EvaluateEscapedChar parse escaped character\nfunc EvaluateEscapedChar(text string) rune {\n\tif len(text) == 1 {\n\t\treturn rune(text[0])\n\t}\n\n\tif len(text) == 2 && text[0] == '\\\\' {\n\t\treturn rune(escapedChars[text[1]])\n\t}\n\n\tif len(text) == 6 && text[0:2] == \"\\\\u\" {\n\t\tn, err := strconv.ParseInt(text[2:], 16, 32)\n\t\tif err == nil {\n\t\t\treturn rune(n)\n\t\t}\n\t}\n\n\treturn 0\n}\n\n// EvaluateEscapedString parse escaped characters in string\nfunc EvaluateEscapedString(text string) string {\n\tif !strings.ContainsRune(text, '\\\\') {\n\t\treturn text\n\t}\n\tresult := make([]byte, 0, len(text))\n\tfor i := 0; i < len(text); i++ {\n\t\tif text[i] == '\\\\' {\n\t\t\ti++\n\t\t\tif text[i] == 'u' {\n\t\t\t\ti++\n\t\t\t\tchar, err := strconv.ParseInt(text[i:i+4], 16, 32)\n\t\t\t\tif err == nil {\n\t\t\t\t\tresult = utf8.AppendRune(result, rune(char))\n\t\t\t\t}\n\t\t\t\ti += 3\n\t\t\t} else if c, ok := escapedChars[text[i]]; ok {\n\t\t\t\tresult = append(result, c)\n\t\t\t}\n\t\t} else {\n\t\t\tresult = append(result, text[i])\n\t\t}\n\t}\n\treturn string(result)\n}\n\n// EvaluateDataConversion evaluate the type a explicit type conversion\nfunc EvaluateDataConversion(x any, typeName string) any {\n\tswitch value := x.(type) {\n\tcase int:\n\t\tswitch typeName {\n\t\tcase \"int\":\n\t\t\treturn int(value)\n\t\tcase \"byte\":\n\t\t\treturn byte(value)\n\t\tcase \"int8\":\n\t\t\treturn int8(value)\n\t\tcase \"int16\":\n\t\t\treturn int16(value)\n\t\tcase \"int32\":\n\t\t\treturn int32(value)\n\t\tcase \"int64\":\n\t\t\treturn int64(value)\n\t\tcase \"uint\":\n\t\t\treturn uint(value)\n\t\tcase \"uint8\":\n\t\t\treturn uint8(value)\n\t\tcase \"uint16\":\n\t\t\treturn uint16(value)\n\t\tcase \"uint32\":\n\t\t\treturn uint32(value)\n\t\tcase \"uint64\":\n\t\t\treturn uint64(value)\n\t\tcase \"rune\":\n\t\t\treturn rune(value)\n\t\t}\n\tcase uint:\n\t\tswitch typeName {\n\t\tcase \"int\":\n\t\t\treturn int(value)\n\t\tcase \"byte\":\n\t\t\treturn byte(value)\n\t\tcase \"int8\":\n\t\t\treturn int8(value)\n\t\tcase \"int16\":\n\t\t\treturn int16(value)\n\t\tcase \"int32\":\n\t\t\treturn int32(value)\n\t\tcase \"int64\":\n\t\t\treturn int64(value)\n\t\tcase \"uint\":\n\t\t\treturn uint(value)\n\t\tcase \"uint8\":\n\t\t\treturn uint8(value)\n\t\tcase \"uint16\":\n\t\t\treturn uint16(value)\n\t\tcase \"uint32\":\n\t\t\treturn uint32(value)\n\t\tcase \"uint64\":\n\t\t\treturn uint64(value)\n\t\tcase \"rune\":\n\t\t\treturn rune(value)\n\t\t}\n\tcase int8:\n\t\tswitch typeName {\n\t\tcase \"int\":\n\t\t\treturn int(value)\n\t\tcase \"byte\":\n\t\t\treturn byte(value)\n\t\tcase \"int8\":\n\t\t\treturn int8(value)\n\t\tcase \"int16\":\n\t\t\treturn int16(value)\n\t\tcase \"int32\":\n\t\t\treturn int32(value)\n\t\tcase \"int64\":\n\t\t\treturn int64(value)\n\t\tcase \"uint\":\n\t\t\treturn uint(value)\n\t\tcase \"uint8\":\n\t\t\treturn uint8(value)\n\t\tcase \"uint16\":\n\t\t\treturn uint16(value)\n\t\tcase \"uint32\":\n\t\t\treturn uint32(value)\n\t\tcase \"uint64\":\n\t\t\treturn uint64(value)\n\t\tcase \"rune\":\n\t\t\treturn rune(value)\n\t\t}\n\tcase uint8:\n\t\tswitch typeName {\n\t\tcase \"int\":\n\t\t\treturn int(value)\n\t\tcase \"byte\":\n\t\t\treturn byte(value)\n\t\tcase \"int8\":\n\t\t\treturn int8(value)\n\t\tcase \"int16\":\n\t\t\treturn int16(value)\n\t\tcase \"int32\":\n\t\t\treturn int32(value)\n\t\tcase \"int64\":\n\t\t\treturn int64(value)\n\t\tcase \"uint\":\n\t\t\treturn uint(value)\n\t\tcase \"uint8\":\n\t\t\treturn uint8(value)\n\t\tcase \"uint16\":\n\t\t\treturn uint16(value)\n\t\tcase \"uint32\":\n\t\t\treturn uint32(value)\n\t\tcase \"uint64\":\n\t\t\treturn uint64(value)\n\t\tcase \"rune\":\n\t\t\treturn rune(value)\n\t\t}\n\tcase int16:\n\t\tswitch typeName {\n\t\tcase \"int\":\n\t\t\treturn int(value)\n\t\tcase \"byte\":\n\t\t\treturn byte(value)\n\t\tcase \"int8\":\n\t\t\treturn int8(value)\n\t\tcase \"int16\":\n\t\t\treturn int16(value)\n\t\tcase \"int32\":\n\t\t\treturn int32(value)\n\t\tcase \"int64\":\n\t\t\treturn int64(value)\n\t\tcase \"uint\":\n\t\t\treturn uint(value)\n\t\tcase \"uint8\":\n\t\t\treturn uint8(value)\n\t\tcase \"uint16\":\n\t\t\treturn uint16(value)\n\t\tcase \"uint32\":\n\t\t\treturn uint32(value)\n\t\tcase \"uint64\":\n\t\t\treturn uint64(value)\n\t\tcase \"rune\":\n\t\t\treturn rune(value)\n\t\t}\n\tcase uint16:\n\t\tswitch typeName {\n\t\tcase \"int\":\n\t\t\treturn int(value)\n\t\tcase \"byte\":\n\t\t\treturn byte(value)\n\t\tcase \"int8\":\n\t\t\treturn int8(value)\n\t\tcase \"int16\":\n\t\t\treturn int16(value)\n\t\tcase \"int32\":\n\t\t\treturn int32(value)\n\t\tcase \"int64\":\n\t\t\treturn int64(value)\n\t\tcase \"uint\":\n\t\t\treturn uint(value)\n\t\tcase \"uint8\":\n\t\t\treturn uint8(value)\n\t\tcase \"uint16\":\n\t\t\treturn uint16(value)\n\t\tcase \"uint32\":\n\t\t\treturn uint32(value)\n\t\tcase \"uint64\":\n\t\t\treturn uint64(value)\n\t\tcase \"rune\":\n\t\t\treturn rune(value)\n\t\t}\n\tcase int32:\n\t\tswitch typeName {\n\t\tcase \"int\":\n\t\t\treturn int(value)\n\t\tcase \"byte\":\n\t\t\treturn byte(value)\n\t\tcase \"int8\":\n\t\t\treturn int8(value)\n\t\tcase \"int16\":\n\t\t\treturn int16(value)\n\t\tcase \"int32\":\n\t\t\treturn int32(value)\n\t\tcase \"int64\":\n\t\t\treturn int64(value)\n\t\tcase \"uint\":\n\t\t\treturn uint(value)\n\t\tcase \"uint8\":\n\t\t\treturn uint8(value)\n\t\tcase \"uint16\":\n\t\t\treturn uint16(value)\n\t\tcase \"uint32\":\n\t\t\treturn uint32(value)\n\t\tcase \"uint64\":\n\t\t\treturn uint64(value)\n\t\tcase \"rune\":\n\t\t\treturn rune(value)\n\t\tcase \"string\":\n\t\t\treturn string(value)\n\t\t}\n\tcase uint32:\n\t\tswitch typeName {\n\t\tcase \"int\":\n\t\t\treturn int(value)\n\t\tcase \"byte\":\n\t\t\treturn byte(value)\n\t\tcase \"int8\":\n\t\t\treturn int8(value)\n\t\tcase \"int16\":\n\t\t\treturn int16(value)\n\t\tcase \"int32\":\n\t\t\treturn int32(value)\n\t\tcase \"int64\":\n\t\t\treturn int64(value)\n\t\tcase \"uint\":\n\t\t\treturn uint(value)\n\t\tcase \"uint8\":\n\t\t\treturn uint8(value)\n\t\tcase \"uint16\":\n\t\t\treturn uint16(value)\n\t\tcase \"uint32\":\n\t\t\treturn uint32(value)\n\t\tcase \"uint64\":\n\t\t\treturn uint64(value)\n\t\tcase \"rune\":\n\t\t\treturn rune(value)\n\t\t}\n\tcase int64:\n\t\tswitch typeName {\n\t\tcase \"int\":\n\t\t\treturn int(value)\n\t\tcase \"byte\":\n\t\t\treturn byte(value)\n\t\tcase \"int8\":\n\t\t\treturn int8(value)\n\t\tcase \"int16\":\n\t\t\treturn int16(value)\n\t\tcase \"int32\":\n\t\t\treturn int32(value)\n\t\tcase \"int64\":\n\t\t\treturn int64(value)\n\t\tcase \"uint\":\n\t\t\treturn uint(value)\n\t\tcase \"uint8\":\n\t\t\treturn uint8(value)\n\t\tcase \"uint16\":\n\t\t\treturn uint16(value)\n\t\tcase \"uint32\":\n\t\t\treturn uint32(value)\n\t\tcase \"uint64\":\n\t\t\treturn uint64(value)\n\t\tcase \"rune\":\n\t\t\treturn rune(value)\n\t\t}\n\tcase uint64:\n\t\tswitch typeName {\n\t\tcase \"int\":\n\t\t\treturn int(value)\n\t\tcase \"byte\":\n\t\t\treturn byte(value)\n\t\tcase \"int8\":\n\t\t\treturn int8(value)\n\t\tcase \"int16\":\n\t\t\treturn int16(value)\n\t\tcase \"int32\":\n\t\t\treturn int32(value)\n\t\tcase \"int64\":\n\t\t\treturn int64(value)\n\t\tcase \"uint\":\n\t\t\treturn uint(value)\n\t\tcase \"uint8\":\n\t\t\treturn uint8(value)\n\t\tcase \"uint16\":\n\t\t\treturn uint16(value)\n\t\tcase \"uint32\":\n\t\t\treturn uint32(value)\n\t\tcase \"uint64\":\n\t\t\treturn uint64(value)\n\t\tcase \"rune\":\n\t\t\treturn rune(value)\n\t\t}\n\tcase string:\n\t\tswitch typeName {\n\t\tcase \"string\":\n\t\t\treturn value\n\t\t}\n\t}\n\treturn nil\n}\n\n// EvaluateUnary evaluate the type and value of a unary expression\nfunc EvaluateUnary(x any, operator token.Token, xtype ast.Expr) (any, ast.Expr) {\n\tswitch operator {\n\tcase token.SUB:\n\t\tswitch value := x.(type) {\n\t\tcase int:\n\t\t\treturn -value, xtype\n\t\tcase int8:\n\t\t\treturn -value, xtype\n\t\tcase int16:\n\t\t\treturn -value, xtype\n\t\tcase int32:\n\t\t\treturn -value, xtype\n\t\tcase int64:\n\t\t\treturn -value, xtype\n\t\t}\n\tcase token.XOR:\n\t\tswitch value := x.(type) {\n\t\tcase int:\n\t\t\treturn ^value, xtype\n\t\tcase int8:\n\t\t\treturn ^value, xtype\n\t\tcase int16:\n\t\t\treturn ^value, xtype\n\t\tcase int32:\n\t\t\treturn ^value, xtype\n\t\tcase int64:\n\t\t\treturn ^value, xtype\n\t\tcase uint:\n\t\t\treturn ^value, xtype\n\t\tcase uint8:\n\t\t\treturn ^value, xtype\n\t\tcase uint16:\n\t\t\treturn ^value, xtype\n\t\tcase uint32:\n\t\t\treturn ^value, xtype\n\t\tcase uint64:\n\t\t\treturn ^value, xtype\n\t\t}\n\t}\n\treturn nil, nil\n}\n\n// EvaluateBinary evaluate the type and value of a binary expression\nfunc EvaluateBinary(x, y any, operator token.Token, xtype, ytype ast.Expr) (any, ast.Expr) {\n\tif operator == token.SHR || operator == token.SHL {\n\t\tvar rightOperand uint64\n\t\tyValue := reflect.ValueOf(y)\n\t\tif yValue.CanUint() {\n\t\t\trightOperand = yValue.Uint()\n\t\t} else if yValue.CanInt() {\n\t\t\trightOperand = uint64(yValue.Int())\n\t\t}\n\n\t\tswitch operator {\n\t\tcase token.SHL:\n\t\t\tswitch xValue := x.(type) {\n\t\t\tcase int:\n\t\t\t\treturn xValue << rightOperand, xtype\n\t\t\tcase int8:\n\t\t\t\treturn xValue << rightOperand, xtype\n\t\t\tcase int16:\n\t\t\t\treturn xValue << rightOperand, xtype\n\t\t\tcase int32:\n\t\t\t\treturn xValue << rightOperand, xtype\n\t\t\tcase int64:\n\t\t\t\treturn xValue << rightOperand, xtype\n\t\t\tcase uint:\n\t\t\t\treturn xValue << rightOperand, xtype\n\t\t\tcase uint8:\n\t\t\t\treturn xValue << rightOperand, xtype\n\t\t\tcase uint16:\n\t\t\t\treturn xValue << rightOperand, xtype\n\t\t\tcase uint32:\n\t\t\t\treturn xValue << rightOperand, xtype\n\t\t\tcase uint64:\n\t\t\t\treturn xValue << rightOperand, xtype\n\t\t\t}\n\t\tcase token.SHR:\n\t\t\tswitch xValue := x.(type) {\n\t\t\tcase int:\n\t\t\t\treturn xValue >> rightOperand, xtype\n\t\t\tcase int8:\n\t\t\t\treturn xValue >> rightOperand, xtype\n\t\t\tcase int16:\n\t\t\t\treturn xValue >> rightOperand, xtype\n\t\t\tcase int32:\n\t\t\t\treturn xValue >> rightOperand, xtype\n\t\t\tcase int64:\n\t\t\t\treturn xValue >> rightOperand, xtype\n\t\t\tcase uint:\n\t\t\t\treturn xValue >> rightOperand, xtype\n\t\t\tcase uint8:\n\t\t\t\treturn xValue >> rightOperand, xtype\n\t\t\tcase uint16:\n\t\t\t\treturn xValue >> rightOperand, xtype\n\t\t\tcase uint32:\n\t\t\t\treturn xValue >> rightOperand, xtype\n\t\t\tcase uint64:\n\t\t\t\treturn xValue >> rightOperand, xtype\n\t\t\t}\n\t\t}\n\t\treturn nil, nil\n\t}\n\n\tevalType := xtype\n\tif evalType == nil {\n\t\tevalType = ytype\n\t}\n\n\txValue := reflect.ValueOf(x)\n\tyValue := reflect.ValueOf(y)\n\tif xValue.Kind() == reflect.String && yValue.Kind() == reflect.String {\n\t\treturn xValue.String() + yValue.String(), evalType\n\t}\n\n\tvar targetValue reflect.Value\n\tif xValue.Kind() != reflect.Int {\n\t\ttargetValue = reflect.New(xValue.Type()).Elem()\n\t} else {\n\t\ttargetValue = reflect.New(yValue.Type()).Elem()\n\t}\n\n\tswitch operator {\n\tcase token.ADD:\n\t\tif xValue.CanInt() && yValue.CanInt() {\n\t\t\ttargetValue.SetInt(xValue.Int() + yValue.Int())\n\t\t} else if xValue.CanUint() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(xValue.Uint() + yValue.Uint())\n\t\t} else if xValue.CanInt() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(uint64(xValue.Int()) + yValue.Uint())\n\t\t} else if xValue.CanUint() && yValue.CanInt() {\n\t\t\ttargetValue.SetUint(xValue.Uint() + uint64(yValue.Int()))\n\t\t}\n\tcase token.SUB:\n\t\tif xValue.CanInt() && yValue.CanInt() {\n\t\t\ttargetValue.SetInt(xValue.Int() - yValue.Int())\n\t\t} else if xValue.CanUint() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(xValue.Uint() - yValue.Uint())\n\t\t} else if xValue.CanInt() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(uint64(xValue.Int()) - yValue.Uint())\n\t\t} else if xValue.CanUint() && yValue.CanInt() {\n\t\t\ttargetValue.SetUint(xValue.Uint() - uint64(yValue.Int()))\n\t\t}\n\tcase token.MUL:\n\t\tif xValue.CanInt() && yValue.CanInt() {\n\t\t\ttargetValue.SetInt(xValue.Int() * yValue.Int())\n\t\t} else if xValue.CanUint() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(xValue.Uint() * yValue.Uint())\n\t\t} else if xValue.CanInt() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(uint64(xValue.Int()) * yValue.Uint())\n\t\t} else if xValue.CanUint() && yValue.CanInt() {\n\t\t\ttargetValue.SetUint(xValue.Uint() * uint64(yValue.Int()))\n\t\t}\n\tcase token.QUO:\n\t\tif xValue.CanInt() && yValue.CanInt() {\n\t\t\ttargetValue.SetInt(xValue.Int() / yValue.Int())\n\t\t} else if xValue.CanUint() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(xValue.Uint() / yValue.Uint())\n\t\t} else if xValue.CanInt() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(uint64(xValue.Int()) / yValue.Uint())\n\t\t} else if xValue.CanUint() && yValue.CanInt() {\n\t\t\ttargetValue.SetUint(xValue.Uint() / uint64(yValue.Int()))\n\t\t}\n\tcase token.REM:\n\t\tif xValue.CanInt() && yValue.CanInt() {\n\t\t\ttargetValue.SetInt(xValue.Int() % yValue.Int())\n\t\t} else if xValue.CanUint() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(xValue.Uint() % yValue.Uint())\n\t\t} else if xValue.CanInt() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(uint64(xValue.Int()) % yValue.Uint())\n\t\t} else if xValue.CanUint() && yValue.CanInt() {\n\t\t\ttargetValue.SetUint(xValue.Uint() % uint64(yValue.Int()))\n\t\t}\n\tcase token.AND:\n\t\tif xValue.CanInt() && yValue.CanInt() {\n\t\t\ttargetValue.SetInt(xValue.Int() & yValue.Int())\n\t\t} else if xValue.CanUint() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(xValue.Uint() & yValue.Uint())\n\t\t} else if xValue.CanInt() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(uint64(xValue.Int()) & yValue.Uint())\n\t\t} else if xValue.CanUint() && yValue.CanInt() {\n\t\t\ttargetValue.SetUint(xValue.Uint() & uint64(yValue.Int()))\n\t\t}\n\tcase token.OR:\n\t\tif xValue.CanInt() && yValue.CanInt() {\n\t\t\ttargetValue.SetInt(xValue.Int() | yValue.Int())\n\t\t} else if xValue.CanUint() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(xValue.Uint() | yValue.Uint())\n\t\t} else if xValue.CanInt() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(uint64(xValue.Int()) | yValue.Uint())\n\t\t} else if xValue.CanUint() && yValue.CanInt() {\n\t\t\ttargetValue.SetUint(xValue.Uint() | uint64(yValue.Int()))\n\t\t}\n\tcase token.XOR:\n\t\tif xValue.CanInt() && yValue.CanInt() {\n\t\t\ttargetValue.SetInt(xValue.Int() ^ yValue.Int())\n\t\t} else if xValue.CanUint() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(xValue.Uint() ^ yValue.Uint())\n\t\t} else if xValue.CanInt() && yValue.CanUint() {\n\t\t\ttargetValue.SetUint(uint64(xValue.Int()) ^ yValue.Uint())\n\t\t} else if xValue.CanUint() && yValue.CanInt() {\n\t\t\ttargetValue.SetUint(xValue.Uint() ^ uint64(yValue.Int()))\n\t\t}\n\t}\n\treturn targetValue.Interface(), evalType\n}\n"
  },
  {
    "path": "doc.go",
    "content": "/*\nPackage swag converts Go annotations to Swagger Documentation 2.0.\nSee https://github.com/swaggo/swag for more information about swag.\n*/\npackage swag // import \"github.com/swaggo/swag\"\n"
  },
  {
    "path": "enums.go",
    "content": "package swag\n\nconst (\n\tenumVarNamesExtension     = \"x-enum-varnames\"\n\tenumCommentsExtension     = \"x-enum-comments\"\n\tenumDescriptionsExtension = \"x-enum-descriptions\"\n)\n\n// EnumValue a model to record an enum consts variable\ntype EnumValue struct {\n\tkey     string\n\tValue   any\n\tComment string\n}\n"
  },
  {
    "path": "enums_test.go",
    "content": "package swag\n\nimport (\n\t\"encoding/json\"\n\t\"math/bits\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestParseGlobalEnums(t *testing.T) {\n\tsearchDir := \"testdata/enums\"\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tp := New()\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\tb, err := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n\n\tconstsPath := \"github.com/swaggo/swag/testdata/enums/consts\"\n\tassert.Equal(t, bits.UintSize, p.packages.packages[constsPath].ConstTable[\"uintSize\"].Value)\n\tassert.Equal(t, int32(62), p.packages.packages[constsPath].ConstTable[\"maxBase\"].Value)\n\tassert.Equal(t, 8, p.packages.packages[constsPath].ConstTable[\"shlByLen\"].Value)\n\tassert.Equal(t, 255, p.packages.packages[constsPath].ConstTable[\"hexnum\"].Value)\n\tassert.Equal(t, 15, p.packages.packages[constsPath].ConstTable[\"octnum\"].Value)\n\tassert.Equal(t, `aa\\nbb\\u8888cc`, p.packages.packages[constsPath].ConstTable[\"nonescapestr\"].Value)\n\tassert.Equal(t, \"aa\\nbb\\u8888cc\", p.packages.packages[constsPath].ConstTable[\"escapestr\"].Value)\n\tassert.Equal(t, 1_000_000, p.packages.packages[constsPath].ConstTable[\"underscored\"].Value)\n\tassert.Equal(t, 0b10001000, p.packages.packages[constsPath].ConstTable[\"binaryInteger\"].Value)\n\tassert.Equal(t, 0o755, p.packages.packages[constsPath].ConstTable[\"octInteger\"].Value)\n\n\ttypesPath := \"github.com/swaggo/swag/testdata/enums/types\"\n\n\tdifficultyEnums := p.packages.packages[typesPath].TypeDefinitions[\"Difficulty\"].Enums\n\tassert.Equal(t, \"Easy\", difficultyEnums[0].key)\n\tassert.Equal(t, \"\", difficultyEnums[0].Comment)\n\tassert.Equal(t, \"Medium\", difficultyEnums[1].key)\n\tassert.Equal(t, \"This one also has a comment\", difficultyEnums[1].Comment)\n\tassert.Equal(t, \"DifficultyHard\", difficultyEnums[2].key)\n\tassert.Equal(t, \"This means really hard\", difficultyEnums[2].Comment)\n\n\tgenericDifficultyEnums := p.packages.packages[typesPath].TypeDefinitions[\"GenericDifficulty\"].Enums\n\tassert.Equal(t, \"GenericEasy\", genericDifficultyEnums[0].key)\n\tassert.Equal(t, \"\", genericDifficultyEnums[0].Comment)\n\tassert.Equal(t, \"GenericMedium\", genericDifficultyEnums[1].key)\n\tassert.Equal(t, \"This one also has a comment\", genericDifficultyEnums[1].Comment)\n\tassert.Equal(t, \"GenericDifficultyHard\", genericDifficultyEnums[2].key)\n\tassert.Equal(t, \"This means really hard\", genericDifficultyEnums[2].Comment)\n\n\tsecurityLevelEnums := p.packages.packages[typesPath].TypeDefinitions[\"SecurityClearance\"].Enums\n\tassert.Equal(t, \"Public\", securityLevelEnums[0].key)\n\tassert.Equal(t, \"\", securityLevelEnums[0].Comment)\n\tassert.Equal(t, \"SecurityClearanceSensitive\", securityLevelEnums[1].key)\n\tassert.Equal(t, \"Name override and comment rules apply here just as above\", securityLevelEnums[1].Comment)\n\tassert.Equal(t, \"SuperSecret\", securityLevelEnums[2].key)\n\tassert.Equal(t, \"This one has a name override and a comment\", securityLevelEnums[2].Comment)\n}\n"
  },
  {
    "path": "example/basic/api/api.go",
    "content": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/example/basic/web\"\n)\n\n// GetStringByInt example\n//\n//\t@Summary\t\tAdd a new pet to the store\n//\t@Description\tget string by ID\n//\t@ID\t\t\t\tget-string-by-int\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Param\t\t\tsome_id\tpath\t\tint\t\t\t\ttrue\t\"Some ID\"\n//\t@Param\t\t\tsome_id\tbody\t\tweb.Pet\t\t\ttrue\t\"Some ID\"\n//\t@Success\t\t200\t\t{string}\tstring\t\t\t\"ok\"\n//\t@Failure\t\t400\t\t{object}\tweb.APIError\t\"We need ID!!\"\n//\t@Failure\t\t404\t\t{object}\tweb.APIError\t\"Can not find ID\"\n//\t@Router\t\t\t/testapi/get-string-by-int/{some_id} [get]\nfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {\n\tvar pet web.Pet\n\tif err := json.NewDecoder(r.Body).Decode(&pet); err != nil {\n\t\t// write your code\n\t\treturn\n\t}\n\n\t// write your code\n}\n\n// GetStructArrayByString example\n//\n//\t@Description\tget struct array by ID\n//\t@ID\t\t\t\tget-struct-array-by-string\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Param\t\t\tsome_id\tpath\t\tstring\t\t\ttrue\t\"Some ID\"\n//\t@Param\t\t\toffset\tquery\t\tint\t\t\t\ttrue\t\"Offset\"\n//\t@Param\t\t\tlimit\tquery\t\tint\t\t\t\ttrue\t\"Offset\"\n//\t@Success\t\t200\t\t{string}\tstring\t\t\t\"ok\"\n//\t@Failure\t\t400\t\t{object}\tweb.APIError\t\"We need ID!!\"\n//\t@Failure\t\t404\t\t{object}\tweb.APIError\t\"Can not find ID\"\n//\t@Router\t\t\t/testapi/get-struct-array-by-string/{some_id} [get]\nfunc GetStructArrayByString(w http.ResponseWriter, r *http.Request) {\n\t// write your code\n}\n\n// Upload example\n//\n//\t@Summary\t\tUpload file\n//\t@Description\tUpload file\n//\t@ID\t\t\t\tfile.upload\n//\t@Accept\t\t\tmultipart/form-data\n//\t@Produce\t\tjson\n//\t@Param\t\t\tfile\tformData\tfile\t\t\ttrue\t\"this is a test file\"\n//\t@Success\t\t200\t\t{string}\tstring\t\t\t\"ok\"\n//\t@Failure\t\t400\t\t{object}\tweb.APIError\t\"We need ID!!\"\n//\t@Failure\t\t404\t\t{object}\tweb.APIError\t\"Can not find ID\"\n//\t@Router\t\t\t/file/upload [post]\nfunc Upload(w http.ResponseWriter, r *http.Request) {\n\t// write your code\n}\n\n// AnonymousField example\n//\n//\t@Summary\tuse Anonymous field\n//\t@Success\t200\t{object}\tweb.RevValue\t\"ok\"\nfunc AnonymousField() {\n\n}\n\n// Pet3 example\ntype Pet3 struct {\n\tID int `json:\"id\"`\n}\n"
  },
  {
    "path": "example/basic/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/example/basic/api\"\n)\n\n//\t@title\t\t\tSwagger Example API\n//\t@version\t\t1.0\n//\t@description\tThis is a sample server Petstore server.\n//\t@termsOfService\thttp://swagger.io/terms/\n\n//\t@contact.name\tAPI Support\n//\t@contact.url\thttp://www.swagger.io/support\n//\t@contact.email\tsupport@swagger.io\n\n//\t@license.name\tApache 2.0\n//\t@license.url\thttp://www.apache.org/licenses/LICENSE-2.0.html\n\n//\t@host\t\tpetstore.swagger.io\n//\t@BasePath\t/v2\n\nfunc main() {\n\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\thttp.HandleFunc(\"//testapi/get-struct-array-by-string/\", api.GetStructArrayByString)\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "example/basic/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n)\n\n// Pet example\ntype Pet struct {\n\tID       int `json:\"id\"`\n\tCategory struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t} `json:\"category\"`\n\tName      string   `json:\"name\"`\n\tPhotoUrls []string `json:\"photoUrls\"`\n\tTags      []Tag    `json:\"tags\"`\n\tStatus    string   `json:\"status\"`\n}\n\n// Tag example\ntype Tag struct {\n\tID   int    `json:\"id\"`\n\tName string `json:\"name\"`\n}\n\n// Pet2 example\ntype Pet2 struct {\n\tID int `json:\"id\"`\n}\n\n// APIError example\ntype APIError struct {\n\tErrorCode    int\n\tErrorMessage string\n\tCreatedAt    time.Time\n}\n\n// RevValueBase example\ntype RevValueBase struct {\n\tStatus bool `json:\"Status\"`\n\n\tErr int32 `json:\"Err\"`\n}\n\n// RevValue example\ntype RevValue struct {\n\tRevValueBase\n\n\tData int `json:\"Data\"`\n}\n"
  },
  {
    "path": "example/celler/README.md",
    "content": "# Celler example\n\nGen doc\n\n```console\n$ go get -u github.com/swaggo/swag/cmd/swag\n$ swag init\n```\n\nRun app\n\n```console\n$ go run main.go\n```\n\n[open swagger](http://localhost:8080/swagger/index.html)\n\n"
  },
  {
    "path": "example/celler/controller/accounts.go",
    "content": "package controller\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/swaggo/swag/example/celler/httputil\"\n\t\"github.com/swaggo/swag/example/celler/model\"\n)\n\n// ShowAccount godoc\n//\n//\t@Summary\t\tShow an account\n//\t@Description\tget string by ID\n//\t@Tags\t\t\taccounts\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Param\t\t\tid\tpath\t\tint\ttrue\t\"Account ID\"\n//\t@Success\t\t200\t{object}\tmodel.Account\n//\t@Failure\t\t400\t{object}\thttputil.HTTPError\n//\t@Failure\t\t404\t{object}\thttputil.HTTPError\n//\t@Failure\t\t500\t{object}\thttputil.HTTPError\n//\t@Router\t\t\t/accounts/{id} [get]\nfunc (c *Controller) ShowAccount(ctx *gin.Context) {\n\tid := ctx.Param(\"id\")\n\taid, err := strconv.Atoi(id)\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\taccount, err := model.AccountOne(aid)\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusNotFound, err)\n\t\treturn\n\t}\n\tctx.JSON(http.StatusOK, account)\n}\n\n// ListAccounts godoc\n//\n//\t@Summary\t\tList accounts\n//\t@Description\tget accounts\n//\t@Tags\t\t\taccounts\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Param\t\t\tq\tquery\t\tstring\tfalse\t\"name search by q\"\tFormat(email)\n//\t@Success\t\t200\t{array}\t\tmodel.Account\n//\t@Failure\t\t400\t{object}\thttputil.HTTPError\n//\t@Failure\t\t404\t{object}\thttputil.HTTPError\n//\t@Failure\t\t500\t{object}\thttputil.HTTPError\n//\t@Router\t\t\t/accounts [get]\nfunc (c *Controller) ListAccounts(ctx *gin.Context) {\n\tq := ctx.Request.URL.Query().Get(\"q\")\n\taccounts, err := model.AccountsAll(q)\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusNotFound, err)\n\t\treturn\n\t}\n\tctx.JSON(http.StatusOK, accounts)\n}\n\n// AddAccount godoc\n//\n//\t@Summary\t\tAdd an account\n//\t@Description\tadd by json account\n//\t@Tags\t\t\taccounts\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Param\t\t\taccount\tbody\t\tmodel.AddAccount\ttrue\t\"Add account\"\n//\t@Success\t\t200\t\t{object}\tmodel.Account\n//\t@Failure\t\t400\t\t{object}\thttputil.HTTPError\n//\t@Failure\t\t404\t\t{object}\thttputil.HTTPError\n//\t@Failure\t\t500\t\t{object}\thttputil.HTTPError\n//\t@Router\t\t\t/accounts [post]\nfunc (c *Controller) AddAccount(ctx *gin.Context) {\n\tvar addAccount model.AddAccount\n\tif err := ctx.ShouldBindJSON(&addAccount); err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\tif err := addAccount.Validation(); err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\taccount := model.Account{\n\t\tName: addAccount.Name,\n\t}\n\tlastID, err := account.Insert()\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\taccount.ID = lastID\n\tctx.JSON(http.StatusOK, account)\n}\n\n// UpdateAccount godoc\n//\n//\t@Summary\t\tUpdate an account\n//\t@Description\tUpdate by json account\n//\t@Tags\t\t\taccounts\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Param\t\t\tid\t\tpath\t\tint\t\t\t\t\ttrue\t\"Account ID\"\n//\t@Param\t\t\taccount\tbody\t\tmodel.UpdateAccount\ttrue\t\"Update account\"\n//\t@Success\t\t200\t\t{object}\tmodel.Account\n//\t@Failure\t\t400\t\t{object}\thttputil.HTTPError\n//\t@Failure\t\t404\t\t{object}\thttputil.HTTPError\n//\t@Failure\t\t500\t\t{object}\thttputil.HTTPError\n//\t@Router\t\t\t/accounts/{id} [patch]\nfunc (c *Controller) UpdateAccount(ctx *gin.Context) {\n\tid := ctx.Param(\"id\")\n\taid, err := strconv.Atoi(id)\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\tvar updateAccount model.UpdateAccount\n\tif err := ctx.ShouldBindJSON(&updateAccount); err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\taccount := model.Account{\n\t\tID:   aid,\n\t\tName: updateAccount.Name,\n\t}\n\terr = account.Update()\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusNotFound, err)\n\t\treturn\n\t}\n\tctx.JSON(http.StatusOK, account)\n}\n\n// DeleteAccount godoc\n//\n//\t@Summary\t\tDelete an account\n//\t@Description\tDelete by account ID\n//\t@Tags\t\t\taccounts\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Param\t\t\tid\tpath\t\tint\ttrue\t\"Account ID\"\tFormat(int64)\n//\t@Success\t\t204\t{object}\tmodel.Account\n//\t@Failure\t\t400\t{object}\thttputil.HTTPError\n//\t@Failure\t\t404\t{object}\thttputil.HTTPError\n//\t@Failure\t\t500\t{object}\thttputil.HTTPError\n//\t@Router\t\t\t/accounts/{id} [delete]\nfunc (c *Controller) DeleteAccount(ctx *gin.Context) {\n\tid := ctx.Param(\"id\")\n\taid, err := strconv.Atoi(id)\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\terr = model.Delete(aid)\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusNotFound, err)\n\t\treturn\n\t}\n\tctx.JSON(http.StatusNoContent, gin.H{})\n}\n\n// UploadAccountImage godoc\n//\n//\t@Summary\t\tUpload account image\n//\t@Description\tUpload file\n//\t@Tags\t\t\taccounts\n//\t@Accept\t\t\tmultipart/form-data\n//\t@Produce\t\tjson\n//\t@Param\t\t\tid\t\tpath\t\tint\t\ttrue\t\"Account ID\"\n//\t@Param\t\t\tfile\tformData\tfile\ttrue\t\"account image\"\n//\t@Success\t\t200\t\t{object}\tcontroller.Message\n//\t@Failure\t\t400\t\t{object}\thttputil.HTTPError\n//\t@Failure\t\t404\t\t{object}\thttputil.HTTPError\n//\t@Failure\t\t500\t\t{object}\thttputil.HTTPError\n//\t@Router\t\t\t/accounts/{id}/images [post]\nfunc (c *Controller) UploadAccountImage(ctx *gin.Context) {\n\tid, err := strconv.Atoi(ctx.Param(\"id\"))\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\tfile, err := ctx.FormFile(\"file\")\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\tctx.JSON(http.StatusOK, Message{Message: fmt.Sprintf(\"upload complete userID=%d filename=%s\", id, file.Filename)})\n}\n"
  },
  {
    "path": "example/celler/controller/admin.go",
    "content": "package controller\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/swaggo/swag/example/celler/httputil\"\n\t\"github.com/swaggo/swag/example/celler/model\"\n)\n\n// Auth godoc\n//\n//\t@Summary\t\tAuth admin\n//\t@Description\tget admin info\n//\t@Tags\t\t\taccounts,admin\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Success\t\t200\t{object}\tmodel.Admin\n//\t@Failure\t\t400\t{object}\thttputil.HTTPError\n//\t@Failure\t\t401\t{object}\thttputil.HTTPError\n//\t@Failure\t\t404\t{object}\thttputil.HTTPError\n//\t@Failure\t\t500\t{object}\thttputil.HTTPError\n//\t@Security\t\tApiKeyAuth\n//\t@Router\t\t\t/admin/auth [post]\nfunc (c *Controller) Auth(ctx *gin.Context) {\n\tauthHeader := ctx.GetHeader(\"Authorization\")\n\tif len(authHeader) == 0 {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, errors.New(\"please set Header Authorization\"))\n\t\treturn\n\t}\n\tif authHeader != \"admin\" {\n\t\thttputil.NewError(ctx, http.StatusUnauthorized, fmt.Errorf(\"this user isn't authorized to operation key=%s expected=admin\", authHeader))\n\t\treturn\n\t}\n\tadmin := model.Admin{\n\t\tID:   1,\n\t\tName: \"admin\",\n\t}\n\tctx.JSON(http.StatusOK, admin)\n}\n"
  },
  {
    "path": "example/celler/controller/bottles.go",
    "content": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/swaggo/swag/example/celler/httputil\"\n\t\"github.com/swaggo/swag/example/celler/model\"\n)\n\n// ShowBottle godoc\n//\n//\t@Summary\t\tShow a bottle\n//\t@Description\tget string by ID\n//\t@ID\t\t\t\tget-string-by-int\n//\t@Tags\t\t\tbottles\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Param\t\t\tid\tpath\t\tint\ttrue\t\"Bottle ID\"\n//\t@Success\t\t200\t{object}\tmodel.Bottle\n//\t@Failure\t\t400\t{object}\thttputil.HTTPError\n//\t@Failure\t\t404\t{object}\thttputil.HTTPError\n//\t@Failure\t\t500\t{object}\thttputil.HTTPError\n//\t@Router\t\t\t/bottles/{id} [get]\nfunc (c *Controller) ShowBottle(ctx *gin.Context) {\n\tid := ctx.Param(\"id\")\n\tbid, err := strconv.Atoi(id)\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\tbottle, err := model.BottleOne(bid)\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusNotFound, err)\n\t\treturn\n\t}\n\tctx.JSON(http.StatusOK, bottle)\n}\n\n// ListBottles godoc\n//\n//\t@Summary\t\tList bottles\n//\t@Description\tget bottles\n//\t@Tags\t\t\tbottles\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Success\t\t200\t{array}\t\tmodel.Bottle\n//\t@Failure\t\t400\t{object}\thttputil.HTTPError\n//\t@Failure\t\t404\t{object}\thttputil.HTTPError\n//\t@Failure\t\t500\t{object}\thttputil.HTTPError\n//\t@Router\t\t\t/bottles [get]\nfunc (c *Controller) ListBottles(ctx *gin.Context) {\n\tbottles, err := model.BottlesAll()\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusNotFound, err)\n\t\treturn\n\t}\n\tctx.JSON(http.StatusOK, bottles)\n}\n"
  },
  {
    "path": "example/celler/controller/controller.go",
    "content": "package controller\n\n// Controller example\ntype Controller struct {\n}\n\n// NewController example\nfunc NewController() *Controller {\n\treturn &Controller{}\n}\n\n// Message example\ntype Message struct {\n\tMessage string `json:\"message\" example:\"message\"`\n}\n"
  },
  {
    "path": "example/celler/controller/examples.go",
    "content": "package controller\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/swaggo/swag/example/celler/httputil\"\n)\n\n// PingExample godoc\n//\n//\t@Summary\t\tping example\n//\t@Description\tdo ping\n//\t@Tags\t\t\texample\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tplain\n//\t@Success\t\t200\t{string}\tstring\t\"pong\"\n//\t@Failure\t\t400\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t404\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t500\t{string}\tstring\t\"ok\"\n//\t@Router\t\t\t/examples/ping [get]\nfunc (c *Controller) PingExample(ctx *gin.Context) {\n\tctx.String(http.StatusOK, \"pong\")\n}\n\n// CalcExample godoc\n//\n//\t@Summary\t\tcalc example\n//\t@Description\tplus\n//\t@Tags\t\t\texample\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tplain\n//\t@Param\t\t\tval1\tquery\t\tint\t\ttrue\t\"used for calc\"\n//\t@Param\t\t\tval2\tquery\t\tint\t\ttrue\t\"used for calc\"\n//\t@Success\t\t200\t\t{integer}\tstring\t\"answer\"\n//\t@Failure\t\t400\t\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t404\t\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t500\t\t{string}\tstring\t\"ok\"\n//\t@Router\t\t\t/examples/calc [get]\nfunc (c *Controller) CalcExample(ctx *gin.Context) {\n\tval1, err := strconv.Atoi(ctx.Query(\"val1\"))\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\tval2, err := strconv.Atoi(ctx.Query(\"val2\"))\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\tans := val1 + val2\n\tctx.String(http.StatusOK, \"%d\", ans)\n}\n\n// PathParamsExample godoc\n//\n//\t@Summary\t\tpath params example\n//\t@Description\tpath params\n//\t@Tags\t\t\texample\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tplain\n//\t@Param\t\t\tgroup_id\tpath\t\tint\t\ttrue\t\"Group ID\"\n//\t@Param\t\t\taccount_id\tpath\t\tint\t\ttrue\t\"Account ID\"\n//\t@Success\t\t200\t\t\t{string}\tstring\t\"answer\"\n//\t@Failure\t\t400\t\t\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t404\t\t\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t500\t\t\t{string}\tstring\t\"ok\"\n//\t@Router\t\t\t/examples/groups/{group_id}/accounts/{account_id} [get]\nfunc (c *Controller) PathParamsExample(ctx *gin.Context) {\n\tgroupID, err := strconv.Atoi(ctx.Param(\"group_id\"))\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\taccountID, err := strconv.Atoi(ctx.Param(\"account_id\"))\n\tif err != nil {\n\t\thttputil.NewError(ctx, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\tctx.String(http.StatusOK, \"group_id=%d account_id=%d\", groupID, accountID)\n}\n\n// HeaderExample godoc\n//\n//\t@Summary\t\tcustome header example\n//\t@Description\tcustome header\n//\t@Tags\t\t\texample\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tplain\n//\t@Param\t\t\tAuthorization\theader\t\tstring\ttrue\t\"Authentication header\"\n//\t@Success\t\t200\t\t\t\t{string}\tstring\t\"answer\"\n//\t@Failure\t\t400\t\t\t\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t404\t\t\t\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t500\t\t\t\t{string}\tstring\t\"ok\"\n//\t@Router\t\t\t/examples/header [get]\nfunc (c *Controller) HeaderExample(ctx *gin.Context) {\n\tctx.String(http.StatusOK, ctx.GetHeader(\"Authorization\"))\n}\n\n// SecuritiesExample godoc\n//\n//\t@Summary\t\tcustome header example\n//\t@Description\tcustome header\n//\t@Tags\t\t\texample\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Param\t\t\tAuthorization\theader\t\tstring\ttrue\t\"Authentication header\"\n//\t@Success\t\t200\t\t\t\t{string}\tstring\t\"answer\"\n//\t@Failure\t\t400\t\t\t\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t404\t\t\t\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t500\t\t\t\t{string}\tstring\t\"ok\"\n//\t@Security\t\tApiKeyAuth\n//\t@Security\t\tOAuth2Implicit[admin, write]\n//\t@Router\t\t\t/examples/securities [get]\nfunc (c *Controller) SecuritiesExample(ctx *gin.Context) {\n}\n\n// AttributeExample godoc\n//\n//\t@Summary\t\tattribute example\n//\t@Description\tattribute\n//\t@Tags\t\t\texample\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tplain\n//\t@Param\t\t\tenumstring\tquery\t\tstring\tfalse\t\"string enums\"\t\tEnums(A, B, C)\n//\t@Param\t\t\tenumint\t\tquery\t\tint\t\tfalse\t\"int enums\"\t\t\tEnums(1, 2, 3)\n//\t@Param\t\t\tenumnumber\tquery\t\tnumber\tfalse\t\"int enums\"\t\t\tEnums(1.1, 1.2, 1.3)\n//\t@Param\t\t\tstring\t\tquery\t\tstring\tfalse\t\"string valid\"\t\tminlength(5)\tmaxlength(10)\n//\t@Param\t\t\tint\t\t\tquery\t\tint\t\tfalse\t\"int valid\"\t\t\tminimum(1)\t\tmaximum(10)\n//\t@Param\t\t\tdefault\t\tquery\t\tstring\tfalse\t\"string default\"\tdefault(A)\n//\t@Success\t\t200\t\t\t{string}\tstring\t\"answer\"\n//\t@Failure\t\t400\t\t\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t404\t\t\t{string}\tstring\t\"ok\"\n//\t@Failure\t\t500\t\t\t{string}\tstring\t\"ok\"\n//\t@Router\t\t\t/examples/attribute [get]\nfunc (c *Controller) AttributeExample(ctx *gin.Context) {\n\tctx.String(http.StatusOK, fmt.Sprintf(\"enumstring=%s enumint=%s enumnumber=%s string=%s int=%s default=%s\",\n\t\tctx.Query(\"enumstring\"),\n\t\tctx.Query(\"enumint\"),\n\t\tctx.Query(\"enumnumber\"),\n\t\tctx.Query(\"string\"),\n\t\tctx.Query(\"int\"),\n\t\tctx.Query(\"default\"),\n\t))\n}\n\n// PostExample godoc\n//\n//\t@Summary\t\tpost request example\n//\t@Description\tpost request example\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tplain\n//\t@Param\t\t\tmessage\tbody\t\tmodel.Account\ttrue\t\"Account Info\"\n//\t@Success\t\t200\t\t{string}\tstring\t\t\t\"success\"\n//\t@Failure\t\t500\t\t{string}\tstring\t\t\t\"fail\"\n//\t@Router\t\t\t/examples/post [post]\nfunc (c *Controller) PostExample(ctx *gin.Context) {\n}\n"
  },
  {
    "path": "example/celler/go.mod",
    "content": "module github.com/swaggo/swag/example/celler\n\ngo 1.24.0\n\nrequire (\n\tgithub.com/gin-gonic/gin v1.9.1\n\tgithub.com/gofrs/uuid v4.2.0+incompatible\n\tgithub.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2\n\tgithub.com/swaggo/gin-swagger v1.4.2\n\tgithub.com/swaggo/swag v1.8.1\n)\n\nrequire (\n\tgithub.com/KyleBanks/depth v1.2.1 // indirect\n\tgithub.com/PuerkitoBio/purell v1.1.1 // indirect\n\tgithub.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect\n\tgithub.com/bytedance/sonic v1.9.1 // indirect\n\tgithub.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect\n\tgithub.com/gabriel-vasile/mimetype v1.4.2 // indirect\n\tgithub.com/gin-contrib/sse v0.1.0 // indirect\n\tgithub.com/go-openapi/jsonpointer v0.19.5 // indirect\n\tgithub.com/go-openapi/jsonreference v0.19.6 // indirect\n\tgithub.com/go-openapi/spec v0.20.4 // indirect\n\tgithub.com/go-openapi/swag v0.19.15 // indirect\n\tgithub.com/go-playground/locales v0.14.1 // indirect\n\tgithub.com/go-playground/universal-translator v0.18.1 // indirect\n\tgithub.com/go-playground/validator/v10 v10.14.0 // indirect\n\tgithub.com/goccy/go-json v0.10.2 // indirect\n\tgithub.com/josharian/intern v1.0.0 // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/klauspost/cpuid/v2 v2.2.4 // indirect\n\tgithub.com/leodido/go-urn v1.2.4 // indirect\n\tgithub.com/mailru/easyjson v0.7.6 // indirect\n\tgithub.com/mattn/go-isatty v0.0.19 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.2 // indirect\n\tgithub.com/pelletier/go-toml/v2 v2.0.8 // indirect\n\tgithub.com/twitchyliquid64/golang-asm v0.15.1 // indirect\n\tgithub.com/ugorji/go/codec v1.2.11 // indirect\n\tgolang.org/x/arch v0.3.0 // indirect\n\tgolang.org/x/crypto v0.45.0 // indirect\n\tgolang.org/x/net v0.47.0 // indirect\n\tgolang.org/x/sys v0.38.0 // indirect\n\tgolang.org/x/text v0.31.0 // indirect\n\tgolang.org/x/tools v0.38.0 // indirect\n\tgoogle.golang.org/protobuf v1.33.0 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "example/celler/go.sum",
    "content": "github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=\ngithub.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=\ngithub.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=\ngithub.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=\ngithub.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=\ngithub.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=\ngithub.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=\ngithub.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=\ngithub.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=\ngithub.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=\ngithub.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=\ngithub.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=\ngithub.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=\ngithub.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=\ngithub.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/gin-contrib/gzip v0.0.3 h1:etUaeesHhEORpZMp18zoOhepboiWnFtXrBZxszWUn4k=\ngithub.com/gin-contrib/gzip v0.0.3/go.mod h1:YxxswVZIqOvcHEQpsSn+QF5guQtO1dCfy0shBPy4jFc=\ngithub.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=\ngithub.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=\ngithub.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=\ngithub.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=\ngithub.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=\ngithub.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=\ngithub.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=\ngithub.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=\ngithub.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=\ngithub.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=\ngithub.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=\ngithub.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=\ngithub.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=\ngithub.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=\ngithub.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=\ngithub.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=\ngithub.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=\ngithub.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=\ngithub.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=\ngithub.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=\ngithub.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=\ngithub.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=\ngithub.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=\ngithub.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=\ngithub.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=\ngithub.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=\ngithub.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=\ngithub.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=\ngithub.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=\ngithub.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=\ngithub.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=\ngithub.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=\ngithub.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=\ngithub.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=\ngithub.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=\ngithub.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=\ngithub.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=\ngithub.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=\ngithub.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=\ngithub.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=\ngithub.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=\ngithub.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=\ngithub.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=\ngithub.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=\ngithub.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=\ngithub.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=\ngithub.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 h1:+iNTcqQJy0OZ5jk6a5NLib47eqXK8uYcPX+O4+cBpEM=\ngithub.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=\ngithub.com/swaggo/gin-swagger v1.4.2 h1:qDs1YrBOTnurDG/JVMc8678KhoS1B1okQGPtIqVz4YU=\ngithub.com/swaggo/gin-swagger v1.4.2/go.mod h1:hmJ1vPn+XjUvnbzjCdUAxVqgraxELxk8x5zAsjCE5mg=\ngithub.com/swaggo/swag v1.7.9/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=\ngithub.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI=\ngithub.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=\ngithub.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=\ngithub.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=\ngithub.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=\ngithub.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=\ngithub.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=\ngithub.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=\ngithub.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=\ngithub.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngolang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=\ngolang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=\ngolang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=\ngolang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=\ngolang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=\ngolang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=\ngolang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=\ngolang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=\ngolang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=\ngolang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=\ngolang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=\ngolang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=\ngoogle.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nrsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=\n"
  },
  {
    "path": "example/celler/httputil/error.go",
    "content": "package httputil\n\nimport \"github.com/gin-gonic/gin\"\n\n// NewError example\nfunc NewError(ctx *gin.Context, status int, err error) {\n\ter := HTTPError{\n\t\tCode:    status,\n\t\tMessage: err.Error(),\n\t}\n\tctx.JSON(status, er)\n}\n\n// HTTPError example\ntype HTTPError struct {\n\tCode    int    `json:\"code\" example:\"400\"`\n\tMessage string `json:\"message\" example:\"status bad request\"`\n}\n"
  },
  {
    "path": "example/celler/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/swaggo/swag/example/celler/controller\"\n\t_ \"github.com/swaggo/swag/example/celler/docs\"\n\t\"github.com/swaggo/swag/example/celler/httputil\"\n\n\tswaggerFiles \"github.com/swaggo/files\"\n\tginSwagger \"github.com/swaggo/gin-swagger\"\n)\n\n//\t@title\t\t\tSwagger Example API\n//\t@version\t\t1.0\n//\t@description\tThis is a sample server celler server.\n//\t@termsOfService\thttp://swagger.io/terms/\n\n//\t@contact.name\tAPI Support\n//\t@contact.url\thttp://www.swagger.io/support\n//\t@contact.email\tsupport@swagger.io\n\n//\t@license.name\tApache 2.0\n//\t@license.url\thttp://www.apache.org/licenses/LICENSE-2.0.html\n\n//\t@host\t\tlocalhost:8080\n//\t@BasePath\t/api/v1\n\n//\t@securityDefinitions.basic\tBasicAuth\n\n//\t@securityDefinitions.apikey\tApiKeyAuth\n//\t@in\t\t\t\t\t\t\theader\n//\t@name\t\t\t\t\t\tAuthorization\n//\t@description\t\t\t\tDescription for what is this security definition being used\n\n//\t@securitydefinitions.oauth2.application\tOAuth2Application\n//\t@tokenUrl\t\t\t\t\t\t\t\thttps://example.com/oauth/token\n//\t@scope.write\t\t\t\t\t\t\tGrants write access\n//\t@scope.admin\t\t\t\t\t\t\tGrants read and write access to administrative information\n\n//\t@securitydefinitions.oauth2.implicit\tOAuth2Implicit\n//\t@authorizationUrl\t\t\t\t\t\thttps://example.com/oauth/authorize\n//\t@scope.write\t\t\t\t\t\t\tGrants write access\n//\t@scope.admin\t\t\t\t\t\t\tGrants read and write access to administrative information\n\n//\t@securitydefinitions.oauth2.password\tOAuth2Password\n//\t@tokenUrl\t\t\t\t\t\t\t\thttps://example.com/oauth/token\n//\t@scope.read\t\t\t\t\t\t\t\tGrants read access\n//\t@scope.write\t\t\t\t\t\t\tGrants write access\n//\t@scope.admin\t\t\t\t\t\t\tGrants read and write access to administrative information\n\n//\t@securitydefinitions.oauth2.accessCode\tOAuth2AccessCode\n//\t@tokenUrl\t\t\t\t\t\t\t\thttps://example.com/oauth/token\n//\t@authorizationUrl\t\t\t\t\t\thttps://example.com/oauth/authorize\n//\t@scope.admin\t\t\t\t\t\t\tGrants read and write access to administrative information\n\nfunc main() {\n\tr := gin.Default()\n\n\tc := controller.NewController()\n\n\tv1 := r.Group(\"/api/v1\")\n\t{\n\t\taccounts := v1.Group(\"/accounts\")\n\t\t{\n\t\t\taccounts.GET(\":id\", c.ShowAccount)\n\t\t\taccounts.GET(\"\", c.ListAccounts)\n\t\t\taccounts.POST(\"\", c.AddAccount)\n\t\t\taccounts.DELETE(\":id\", c.DeleteAccount)\n\t\t\taccounts.PATCH(\":id\", c.UpdateAccount)\n\t\t\taccounts.POST(\":id/images\", c.UploadAccountImage)\n\t\t}\n\t\tbottles := v1.Group(\"/bottles\")\n\t\t{\n\t\t\tbottles.GET(\":id\", c.ShowBottle)\n\t\t\tbottles.GET(\"\", c.ListBottles)\n\t\t}\n\t\tadmin := v1.Group(\"/admin\")\n\t\t{\n\t\t\tadmin.Use(auth())\n\t\t\tadmin.POST(\"/auth\", c.Auth)\n\t\t}\n\t\texamples := v1.Group(\"/examples\")\n\t\t{\n\t\t\texamples.GET(\"ping\", c.PingExample)\n\t\t\texamples.GET(\"calc\", c.CalcExample)\n\t\t\texamples.GET(\"groups/:group_id/accounts/:account_id\", c.PathParamsExample)\n\t\t\texamples.GET(\"header\", c.HeaderExample)\n\t\t\texamples.GET(\"securities\", c.SecuritiesExample)\n\t\t\texamples.GET(\"attribute\", c.AttributeExample)\n\t\t}\n\t}\n\tr.GET(\"/swagger/*any\", ginSwagger.WrapHandler(swaggerFiles.Handler))\n\tr.Run(\":8080\")\n}\n\nfunc auth() gin.HandlerFunc {\n\treturn func(c *gin.Context) {\n\t\tif len(c.GetHeader(\"Authorization\")) == 0 {\n\t\t\thttputil.NewError(c, http.StatusUnauthorized, errors.New(\"Authorization is required Header\"))\n\t\t\tc.Abort()\n\t\t}\n\t\tc.Next()\n\t}\n}\n"
  },
  {
    "path": "example/celler/model/account.go",
    "content": "package model\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\tuuid \"github.com/gofrs/uuid\"\n)\n\n// Account example\ntype Account struct {\n\tID   int       `json:\"id\" example:\"1\" format:\"int64\"`\n\tName string    `json:\"name\" example:\"account name\"`\n\tUUID uuid.UUID `json:\"uuid\" example:\"550e8400-e29b-41d4-a716-446655440000\" format:\"uuid\"`\n}\n\n// example\nvar (\n\tErrNameInvalid = errors.New(\"name is empty\")\n)\n\n// AddAccount example\ntype AddAccount struct {\n\tName string `json:\"name\" example:\"account name\"`\n}\n\n// Validation example\nfunc (a AddAccount) Validation() error {\n\tswitch {\n\tcase len(a.Name) == 0:\n\t\treturn ErrNameInvalid\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// UpdateAccount example\ntype UpdateAccount struct {\n\tName string `json:\"name\" example:\"account name\"`\n}\n\n// Validation example\nfunc (a UpdateAccount) Validation() error {\n\tswitch {\n\tcase len(a.Name) == 0:\n\t\treturn ErrNameInvalid\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// AccountsAll example\nfunc AccountsAll(q string) ([]Account, error) {\n\tif q == \"\" {\n\t\treturn accounts, nil\n\t}\n\tas := []Account{}\n\tfor k, v := range accounts {\n\t\tif q == v.Name {\n\t\t\tas = append(as, accounts[k])\n\t\t}\n\t}\n\treturn as, nil\n}\n\n// AccountOne example\nfunc AccountOne(id int) (Account, error) {\n\tfor _, v := range accounts {\n\t\tif id == v.ID {\n\t\t\treturn v, nil\n\t\t}\n\t}\n\treturn Account{}, ErrNoRow\n}\n\n// Insert example\nfunc (a Account) Insert() (int, error) {\n\taccountMaxID++\n\ta.ID = accountMaxID\n\ta.Name = fmt.Sprintf(\"account_%d\", accountMaxID)\n\taccounts = append(accounts, a)\n\treturn accountMaxID, nil\n}\n\n// Delete example\nfunc Delete(id int) error {\n\tfor k, v := range accounts {\n\t\tif id == v.ID {\n\t\t\taccounts = append(accounts[:k], accounts[k+1:]...)\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn fmt.Errorf(\"account id=%d is not found\", id)\n}\n\n// Update example\nfunc (a Account) Update() error {\n\tfor k, v := range accounts {\n\t\tif a.ID == v.ID {\n\t\t\taccounts[k].Name = a.Name\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn fmt.Errorf(\"account id=%d is not found\", a.ID)\n}\n\nvar accountMaxID = 3\nvar accounts = []Account{\n\t{ID: 1, Name: \"account_1\"},\n\t{ID: 2, Name: \"account_2\"},\n\t{ID: 3, Name: \"account_3\"},\n}\n"
  },
  {
    "path": "example/celler/model/admin.go",
    "content": "package model\n\n// Admin example\ntype Admin struct {\n\tID   int    `json:\"id\" example:\"1\"`\n\tName string `json:\"name\" example:\"admin name\"`\n}\n"
  },
  {
    "path": "example/celler/model/bottle.go",
    "content": "package model\n\n// Bottle example\ntype Bottle struct {\n\tID      int     `json:\"id\" example:\"1\"`\n\tName    string  `json:\"name\" example:\"bottle_name\"`\n\tAccount Account `json:\"account\"`\n}\n\n// BottlesAll example\nfunc BottlesAll() ([]Bottle, error) {\n\treturn bottles, nil\n}\n\n// BottleOne example\nfunc BottleOne(id int) (*Bottle, error) {\n\tfor _, v := range bottles {\n\t\tif id == v.ID {\n\t\t\treturn &v, nil\n\t\t}\n\t}\n\treturn nil, ErrNoRow\n}\n\nvar bottles = []Bottle{\n\t{ID: 1, Name: \"bottle_1\", Account: Account{ID: 1, Name: \"accout_1\"}},\n\t{ID: 2, Name: \"bottle_2\", Account: Account{ID: 2, Name: \"accout_2\"}},\n\t{ID: 3, Name: \"bottle_3\", Account: Account{ID: 3, Name: \"accout_3\"}},\n}\n"
  },
  {
    "path": "example/celler/model/error.go",
    "content": "package model\n\nimport \"errors\"\n\nvar (\n\t// ErrNoRow example\n\tErrNoRow = errors.New(\"no rows in result set\")\n)\n"
  },
  {
    "path": "example/go-module-support/docs/docs.go",
    "content": "// Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n// This file was generated by swaggo/swag\npackage docs\n\nimport \"github.com/swaggo/swag\"\n\nconst docTemplate = `{\n    \"schemes\": {{ marshal .Schemes }},\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"{{escape .Description}}\",\n        \"title\": \"{{.Title}}\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"{{.Version}}\"\n    },\n    \"host\": \"{{.Host}}\",\n    \"basePath\": \"{{.BasePath}}\",\n    \"paths\": {}\n}`\n\n// SwaggerInfo holds exported Swagger Info so clients can modify it\nvar SwaggerInfo = &swag.Spec{\n\tVersion:          \"1.0\",\n\tHost:             \"petstore.swagger.io\",\n\tBasePath:         \"/v2\",\n\tSchemes:          []string{},\n\tTitle:            \"Swagger Example API\",\n\tDescription:      \"This is a sample server Petstore server.\",\n\tInfoInstanceName: \"swagger\",\n\tSwaggerTemplate:  docTemplate,\n}\n\nfunc init() {\n\tswag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)\n}\n"
  },
  {
    "path": "example/go-module-support/docs/swagger.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {}\n}"
  },
  {
    "path": "example/go-module-support/docs/swagger.yaml",
    "content": "basePath: /v2\nhost: petstore.swagger.io\ninfo:\n  contact:\n    email: support@swagger.io\n    name: API Support\n    url: http://www.swagger.io/support\n  description: This is a sample server Petstore server.\n  license:\n    name: Apache 2.0\n    url: http://www.apache.org/licenses/LICENSE-2.0.html\n  termsOfService: http://swagger.io/terms/\n  title: Swagger Example API\n  version: \"1.0\"\npaths: {}\nswagger: \"2.0\"\n"
  },
  {
    "path": "example/go-module-support/go.mod",
    "content": "module github.com/swaggo/swag/example/go-module-support\n\ngo 1.24.0\n\nrequire (\n\tgithub.com/gin-gonic/gin v1.9.1\n\tgithub.com/swaggo/examples v0.0.0-20190624100559-f57286ab550c\n\tgithub.com/swaggo/swag v1.8.1\n)\n\nrequire (\n\tgithub.com/KyleBanks/depth v1.2.1 // indirect\n\tgithub.com/PuerkitoBio/purell v1.1.1 // indirect\n\tgithub.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect\n\tgithub.com/bytedance/sonic v1.9.1 // indirect\n\tgithub.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect\n\tgithub.com/gabriel-vasile/mimetype v1.4.2 // indirect\n\tgithub.com/gin-contrib/sse v0.1.0 // indirect\n\tgithub.com/go-openapi/jsonpointer v0.19.5 // indirect\n\tgithub.com/go-openapi/jsonreference v0.19.6 // indirect\n\tgithub.com/go-openapi/spec v0.20.4 // indirect\n\tgithub.com/go-openapi/swag v0.19.15 // indirect\n\tgithub.com/go-playground/locales v0.14.1 // indirect\n\tgithub.com/go-playground/universal-translator v0.18.1 // indirect\n\tgithub.com/go-playground/validator/v10 v10.14.0 // indirect\n\tgithub.com/goccy/go-json v0.10.2 // indirect\n\tgithub.com/josharian/intern v1.0.0 // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/klauspost/cpuid/v2 v2.2.4 // indirect\n\tgithub.com/leodido/go-urn v1.2.4 // indirect\n\tgithub.com/mailru/easyjson v0.7.6 // indirect\n\tgithub.com/mattn/go-isatty v0.0.19 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.2 // indirect\n\tgithub.com/pelletier/go-toml/v2 v2.0.8 // indirect\n\tgithub.com/twitchyliquid64/golang-asm v0.15.1 // indirect\n\tgithub.com/ugorji/go/codec v1.2.11 // indirect\n\tgolang.org/x/arch v0.3.0 // indirect\n\tgolang.org/x/crypto v0.45.0 // indirect\n\tgolang.org/x/net v0.47.0 // indirect\n\tgolang.org/x/sys v0.38.0 // indirect\n\tgolang.org/x/text v0.31.0 // indirect\n\tgolang.org/x/tools v0.38.0 // indirect\n\tgoogle.golang.org/protobuf v1.33.0 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "example/go-module-support/go.sum",
    "content": "github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=\ngithub.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=\ngithub.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=\ngithub.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=\ngithub.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=\ngithub.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=\ngithub.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=\ngithub.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=\ngithub.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=\ngithub.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=\ngithub.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=\ngithub.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=\ngithub.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=\ngithub.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=\ngithub.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=\ngithub.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=\ngithub.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=\ngithub.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=\ngithub.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=\ngithub.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=\ngithub.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=\ngithub.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=\ngithub.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=\ngithub.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=\ngithub.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=\ngithub.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=\ngithub.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=\ngithub.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=\ngithub.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=\ngithub.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=\ngithub.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=\ngithub.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=\ngithub.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=\ngithub.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=\ngithub.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=\ngithub.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=\ngithub.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=\ngithub.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=\ngithub.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=\ngithub.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=\ngithub.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=\ngithub.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=\ngithub.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=\ngithub.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=\ngithub.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=\ngithub.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=\ngithub.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=\ngithub.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=\ngithub.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=\ngithub.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/swaggo/examples v0.0.0-20190624100559-f57286ab550c h1:wgBp6VweQ9dML4cKbjh0sV0xxvxgqCrCRiHG6losLv4=\ngithub.com/swaggo/examples v0.0.0-20190624100559-f57286ab550c/go.mod h1:U21M3+8BIXRyR/pwjJ7X0D36sVTzFMiOyUAdgvVfUVI=\ngithub.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI=\ngithub.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=\ngithub.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=\ngithub.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=\ngithub.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=\ngithub.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=\ngolang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=\ngolang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=\ngolang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=\ngolang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=\ngolang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=\ngolang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=\ngolang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=\ngolang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=\ngolang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=\ngolang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=\ngolang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=\ngolang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=\ngolang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=\ngolang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=\ngolang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=\ngoogle.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=\ngoogle.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nrsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=\n"
  },
  {
    "path": "example/go-module-support/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/swaggo/examples/go-module-support/api\" // included package from external\n)\n\n//\t@title\t\t\tSwagger Example API\n//\t@version\t\t1.0\n//\t@description\tThis is a sample server Petstore server.\n//\t@termsOfService\thttp://swagger.io/terms/\n\n//\t@contact.name\tAPI Support\n//\t@contact.url\thttp://www.swagger.io/support\n//\t@contact.email\tsupport@swagger.io\n\n//\t@license.name\tApache 2.0\n//\t@license.url\thttp://www.apache.org/licenses/LICENSE-2.0.html\n\n//\t@host\t\tpetstore.swagger.io\n//\t@BasePath\t/v2\n\nfunc main() {\n\tr := gin.New()\n\tr.GET(\"/testapi/get-string-by-int/:some_id\", api.GetStringByInt)\n\tr.GET(\"//testapi/get-struct-array-by-string/:some_id\", api.GetStructArrayByString)\n\tr.Run()\n\n}\n"
  },
  {
    "path": "example/go-module-support/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n)\n\n// Pet example\ntype Pet struct {\n\tID       int `json:\"id\"`\n\tCategory struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t} `json:\"category\"`\n\tName      string   `json:\"name\"`\n\tPhotoUrls []string `json:\"photoUrls\"`\n\tTags      []Tag    `json:\"tags\"`\n\tStatus    string   `json:\"status\"`\n}\n\n// Tag example\ntype Tag struct {\n\tID   int    `json:\"id\"`\n\tName string `json:\"name\"`\n}\n\n// Pet2 example\ntype Pet2 struct {\n\tID int `json:\"id\"`\n}\n\n// APIError example\ntype APIError struct {\n\tErrorCode    int\n\tErrorMessage string\n\tCreatedAt    time.Time\n}\n\n// RevValueBase example\ntype RevValueBase struct {\n\tStatus bool `json:\"Status\"`\n\n\tErr int32 `json:\"Err\"`\n}\n\n// RevValue example\ntype RevValue struct {\n\tRevValueBase\n\n\tData int `json:\"Data\"`\n}\n"
  },
  {
    "path": "example/markdown/admin.md",
    "content": "# Admin TAG API documentation\n\n**Admin** functions goes here \n\nFor more info please read [link](/docs/readme.md).\n\n"
  },
  {
    "path": "example/markdown/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\t\"time\"\n)\n\n// User example\ntype User struct {\n\tID       int64\n\tEmail    string\n\tPassword string\n}\n\n// UsersCollection example\ntype UsersCollection []User\n\n// Error example\ntype APIError struct {\n\tErrorCode    int\n\tErrorMessage string\n\tCreatedAt    time.Time\n}\n\n// ListUsers example\n//\n//\t@Summary\tList users from the store\n//\t@Tags\t\tadmin\n//\t@Accept\t\tjson\n//\t@Produce\tjson\n//\t@Success\t200\t{array}\tapi.UsersCollection\t\"ok\"\n//\t@Router\t\t/admin/user/ [get]\nfunc ListUsers(w http.ResponseWriter, r *http.Request) {\n\t// write your code\n}\n\n// GetUser example\n//\n//\t@Summary\tRead user from the store\n//\t@Tags\t\tadmin\n//\t@Accept\t\tjson\n//\t@Produce\tjson\n//\t@Param\t\tid\tpath\t\tint\ttrue\t\"User Id\"\n//\t@Success\t200\t{object}\tapi.User\n//\t@Failure\t400\t{object}\tapi.APIError\t\"We need ID!!\"\n//\t@Failure\t404\t{object}\tapi.APIError\t\"Can not find ID\"\n//\t@Router\t\t/admin/user/{id} [get]\nfunc GetUser(w http.ResponseWriter, r *http.Request) {\n\t// write your code\n}\n\n// AddUser example\n//\n//\t@Summary\tAdd a new user to the store\n//\t@Tags\t\tadmin\n//\t@Accept\t\tjson\n//\t@Produce\tjson\n//\t@Param\t\tmessage\tbody\t\tapi.User\t\ttrue\t\"User Data\"\n//\t@Success\t200\t\t{string}\tstring\t\t\t\"ok\"\n//\t@Failure\t400\t\t{object}\tapi.APIError\t\"We need ID!!\"\n//\t@Failure\t404\t\t{object}\tapi.APIError\t\"Can not find ID\"\n//\t@Router\t\t/admin/user/ [post]\nfunc AddUser(w http.ResponseWriter, r *http.Request) {\n\t// write your code\n}\n\n// UpdateUser example\n//\n//\t@Summary\tAdd a new user to the store\n//\t@Tags\t\tadmin\n//\t@Accept\t\tjson\n//\t@Produce\tjson\n//\t@Param\t\tmessage\tbody\t\tapi.User\t\ttrue\t\"User Data\"\n//\t@Success\t200\t\t{string}\tstring\t\t\t\"ok\"\n//\t@Failure\t400\t\t{object}\tapi.APIError\t\"We need ID!!\"\n//\t@Failure\t404\t\t{object}\tapi.APIError\t\"Can not find ID\"\n//\t@Router\t\t/admin/user/ [put]\nfunc UpdateUser(w http.ResponseWriter, r *http.Request) {\n\t// write your code\n}\n"
  },
  {
    "path": "example/markdown/api.md",
    "content": "# General API documentation\n\n**Warning** this api is not production ready. Use at your own risk.\n\nIn order to re-generate the documentation you need to run\n\n`swag init --md .`\n"
  },
  {
    "path": "example/markdown/docs/docs.go",
    "content": "// Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n// This file was generated by swaggo/swag\npackage docs\n\nimport \"github.com/swaggo/swag\"\n\nconst docTemplate = `{\n    \"schemes\": {{ marshal .Schemes }},\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"{{escape .Description}}\",\n        \"title\": \"{{.Title}}\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"{{.Version}}\"\n    },\n    \"host\": \"{{.Host}}\",\n    \"basePath\": \"{{.BasePath}}\",\n    \"paths\": {\n        \"/admin/user/\": {\n            \"get\": {\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"tags\": [\n                    \"admin\"\n                ],\n                \"summary\": \"List users from the store\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/definitions/api.User\"\n                                }\n                            }\n                        }\n                    }\n                }\n            },\n            \"put\": {\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"tags\": [\n                    \"admin\"\n                ],\n                \"summary\": \"Add a new user to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"User Data\",\n                        \"name\": \"message\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.User\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    }\n                }\n            },\n            \"post\": {\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"tags\": [\n                    \"admin\"\n                ],\n                \"summary\": \"Add a new user to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"User Data\",\n                        \"name\": \"message\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.User\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/admin/user/{id}\": {\n            \"get\": {\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"tags\": [\n                    \"admin\"\n                ],\n                \"summary\": \"Read user from the store\",\n                \"parameters\": [\n                    {\n                        \"type\": \"integer\",\n                        \"description\": \"User Id\",\n                        \"name\": \"id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.User\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"api.APIError\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"createdAt\": {\n                    \"type\": \"string\"\n                },\n                \"errorCode\": {\n                    \"type\": \"integer\"\n                },\n                \"errorMessage\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.User\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"email\": {\n                    \"type\": \"string\"\n                },\n                \"id\": {\n                    \"type\": \"integer\"\n                },\n                \"password\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    },\n    \"tags\": [\n        {\n            \"description\": \"# Admin TAG API documentation\\n\\n**Admin** functions goes here \\n\\nFor more info please read [link](/docs/readme.md).\\n\\n\",\n            \"name\": \"admin\"\n        }\n    ]\n}`\n\n// SwaggerInfo holds exported Swagger Info so clients can modify it\nvar SwaggerInfo = &swag.Spec{\n\tVersion:          \"1.0\",\n\tHost:             \"\",\n\tBasePath:         \"/v2\",\n\tSchemes:          []string{},\n\tTitle:            \"Swagger Example API\",\n\tDescription:      \"# General API documentation\\n\\n**Warning** this api is not production ready. Use at your own risk.\\n\\nIn order to re-generate the documentation you need to run\\n\\n`swag init --md .`\\n\",\n\tInfoInstanceName: \"swagger\",\n\tSwaggerTemplate:  docTemplate,\n}\n\nfunc init() {\n\tswag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)\n}\n"
  },
  {
    "path": "example/markdown/docs/swagger.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"# General API documentation\\n\\n**Warning** this api is not production ready. Use at your own risk.\\n\\nIn order to re-generate the documentation you need to run\\n\\n`swag init --md .`\\n\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"basePath\": \"/v2\",\n    \"paths\": {\n        \"/admin/user/\": {\n            \"get\": {\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"tags\": [\n                    \"admin\"\n                ],\n                \"summary\": \"List users from the store\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/definitions/api.User\"\n                                }\n                            }\n                        }\n                    }\n                }\n            },\n            \"put\": {\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"tags\": [\n                    \"admin\"\n                ],\n                \"summary\": \"Add a new user to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"User Data\",\n                        \"name\": \"message\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.User\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    }\n                }\n            },\n            \"post\": {\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"tags\": [\n                    \"admin\"\n                ],\n                \"summary\": \"Add a new user to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"User Data\",\n                        \"name\": \"message\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.User\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/admin/user/{id}\": {\n            \"get\": {\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"tags\": [\n                    \"admin\"\n                ],\n                \"summary\": \"Read user from the store\",\n                \"parameters\": [\n                    {\n                        \"type\": \"integer\",\n                        \"description\": \"User Id\",\n                        \"name\": \"id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.User\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.APIError\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"api.APIError\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"createdAt\": {\n                    \"type\": \"string\"\n                },\n                \"errorCode\": {\n                    \"type\": \"integer\"\n                },\n                \"errorMessage\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.User\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"email\": {\n                    \"type\": \"string\"\n                },\n                \"id\": {\n                    \"type\": \"integer\"\n                },\n                \"password\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    },\n    \"tags\": [\n        {\n            \"description\": \"# Admin TAG API documentation\\n\\n**Admin** functions goes here \\n\\nFor more info please read [link](/docs/readme.md).\\n\\n\",\n            \"name\": \"admin\"\n        }\n    ]\n}"
  },
  {
    "path": "example/markdown/docs/swagger.yaml",
    "content": "basePath: /v2\ndefinitions:\n  api.APIError:\n    properties:\n      createdAt:\n        type: string\n      errorCode:\n        type: integer\n      errorMessage:\n        type: string\n    type: object\n  api.User:\n    properties:\n      email:\n        type: string\n      id:\n        type: integer\n      password:\n        type: string\n    type: object\ninfo:\n  contact:\n    email: support@swagger.io\n    name: API Support\n    url: http://www.swagger.io/support\n  description: |\n    # General API documentation\n\n    **Warning** this api is not production ready. Use at your own risk.\n\n    In order to re-generate the documentation you need to run\n\n    `swag init --md .`\n  license:\n    name: Apache 2.0\n    url: http://www.apache.org/licenses/LICENSE-2.0.html\n  termsOfService: http://swagger.io/terms/\n  title: Swagger Example API\n  version: \"1.0\"\npaths:\n  /admin/user/:\n    get:\n      consumes:\n      - application/json\n      produces:\n      - application/json\n      responses:\n        \"200\":\n          description: ok\n          schema:\n            items:\n              items:\n                $ref: '#/definitions/api.User'\n              type: array\n            type: array\n      summary: List users from the store\n      tags:\n      - admin\n    post:\n      consumes:\n      - application/json\n      parameters:\n      - description: User Data\n        in: body\n        name: message\n        required: true\n        schema:\n          $ref: '#/definitions/api.User'\n      produces:\n      - application/json\n      responses:\n        \"200\":\n          description: ok\n          schema:\n            type: string\n        \"400\":\n          description: We need ID!!\n          schema:\n            $ref: '#/definitions/api.APIError'\n        \"404\":\n          description: Can not find ID\n          schema:\n            $ref: '#/definitions/api.APIError'\n      summary: Add a new user to the store\n      tags:\n      - admin\n    put:\n      consumes:\n      - application/json\n      parameters:\n      - description: User Data\n        in: body\n        name: message\n        required: true\n        schema:\n          $ref: '#/definitions/api.User'\n      produces:\n      - application/json\n      responses:\n        \"200\":\n          description: ok\n          schema:\n            type: string\n        \"400\":\n          description: We need ID!!\n          schema:\n            $ref: '#/definitions/api.APIError'\n        \"404\":\n          description: Can not find ID\n          schema:\n            $ref: '#/definitions/api.APIError'\n      summary: Add a new user to the store\n      tags:\n      - admin\n  /admin/user/{id}:\n    get:\n      consumes:\n      - application/json\n      parameters:\n      - description: User Id\n        in: path\n        name: id\n        required: true\n        type: integer\n      produces:\n      - application/json\n      responses:\n        \"200\":\n          description: OK\n          schema:\n            $ref: '#/definitions/api.User'\n        \"400\":\n          description: We need ID!!\n          schema:\n            $ref: '#/definitions/api.APIError'\n        \"404\":\n          description: Can not find ID\n          schema:\n            $ref: '#/definitions/api.APIError'\n      summary: Read user from the store\n      tags:\n      - admin\nswagger: \"2.0\"\ntags:\n- description: \"# Admin TAG API documentation\\n\\n**Admin** functions goes here \\n\\nFor\n    more info please read [link](/docs/readme.md).\\n\\n\"\n  name: admin\n"
  },
  {
    "path": "example/markdown/go.mod",
    "content": "module github.com/swaggo/swag/example/markdown\n\ngo 1.18\n\nrequire (\n\tgithub.com/gorilla/mux v1.8.0\n\tgithub.com/swaggo/http-swagger v1.2.6\n\tgithub.com/swaggo/swag v1.8.1\n)\n\nrequire (\n\tgithub.com/KyleBanks/depth v1.2.1 // indirect\n\tgithub.com/go-openapi/jsonpointer v0.19.5 // indirect\n\tgithub.com/go-openapi/jsonreference v0.20.0 // indirect\n\tgithub.com/go-openapi/spec v0.20.5 // indirect\n\tgithub.com/go-openapi/swag v0.19.15 // indirect\n\tgithub.com/josharian/intern v1.0.0 // indirect\n\tgithub.com/mailru/easyjson v0.7.6 // indirect\n\tgithub.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 // indirect\n\tgolang.org/x/net v0.38.0 // indirect\n\tgolang.org/x/sys v0.31.0 // indirect\n\tgolang.org/x/tools v0.1.10 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n)\n"
  },
  {
    "path": "example/markdown/go.sum",
    "content": "github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=\ngithub.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=\ngithub.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=\ngithub.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=\ngithub.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=\ngithub.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=\ngithub.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=\ngithub.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=\ngithub.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=\ngithub.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=\ngithub.com/go-openapi/spec v0.20.5 h1:skHa8av4VnAtJU5zyAUXrrdK/NDiVX8lchbG+BfcdrE=\ngithub.com/go-openapi/spec v0.20.5/go.mod h1:QbfOSIVt3/sac+a1wzmKbbcLXm5NdZnyBZYtCijp43o=\ngithub.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=\ngithub.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=\ngithub.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=\ngithub.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=\ngithub.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=\ngithub.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=\ngithub.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=\ngithub.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=\ngithub.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=\ngithub.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=\ngithub.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=\ngithub.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 h1:+iNTcqQJy0OZ5jk6a5NLib47eqXK8uYcPX+O4+cBpEM=\ngithub.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=\ngithub.com/swaggo/http-swagger v1.2.6 h1:ihTjChUoSRMpFMjWw+0AkL1Ti4r6v8pCgVYLmQVRlRw=\ngithub.com/swaggo/http-swagger v1.2.6/go.mod h1:CcoICgY3yVDk2u1LQUCMHbAj0fjlxIX+873psXlIKNA=\ngithub.com/swaggo/swag v1.7.9/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=\ngithub.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI=\ngithub.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=\ngithub.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=\ngithub.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=\ngolang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=\ngolang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=\ngolang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=\ngolang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=\ngolang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=\ngopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "example/markdown/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\thttpSwagger \"github.com/swaggo/http-swagger\"\n\t\"github.com/swaggo/swag/example/markdown/api\"\n\t_ \"github.com/swaggo/swag/example/markdown/docs\"\n)\n\n//\t@title\t\t\tSwagger Example API\n//\t@version\t\t1.0\n//\t@description\tThis is a sample server Petstore server.\n//\t@description.markdown\n//\t@termsOfService\thttp://swagger.io/terms/\n\n//\t@contact.name\tAPI Support\n//\t@contact.url\thttp://www.swagger.io/support\n//\t@contact.email\tsupport@swagger.io\n\n//\t@license.name\tApache 2.0\n//\t@license.url\thttp://www.apache.org/licenses/LICENSE-2.0.html\n\n//\t@tag.name\tadmin\n//\t@tag.description.markdown\n\n//\t@BasePath\t/v2\n\nfunc main() {\n\trouter := mux.NewRouter()\n\n\trouter.HandleFunc(\"/admin/user/\", api.ListUsers).Methods(\"GET\")\n\trouter.HandleFunc(\"/admin/user/{id}\", api.GetUser).Methods(\"GET\")\n\trouter.HandleFunc(\"/admin/user/\", api.AddUser).Methods(\"POST\")\n\trouter.HandleFunc(\"/admin/user/{id}\", api.UpdateUser).Methods(\"PUT\")\n\n\trouter.PathPrefix(\"/swagger/\").Handler(httpSwagger.WrapHandler)\n\thttp.ListenAndServe(\":8080\", router)\n}\n"
  },
  {
    "path": "example/object-map-example/controller/api.go",
    "content": "package controller\n\nimport \"github.com/gin-gonic/gin\"\n\n// GetMap godoc\n//\n//\t@Summary\t\tGet Map Example\n//\t@Description\tget map\n//\t@ID\t\t\t\tget-map\n//\t@Accept\t\t\tjson\n//\t@Produce\t\tjson\n//\t@Success\t\t200\t{object}\tResponse\n//\t@Router\t\t\t/test [get]\nfunc (c *Controller) GetMap(ctx *gin.Context) {\n\tctx.JSON(200, Response{\n\t\tTitle: map[string]string{\n\t\t\t\"en\": \"Map\",\n\t\t},\n\t\tCustomType: map[string]interface{}{\n\t\t\t\"key\": \"value\",\n\t\t},\n\t\tObject: Data{\n\t\t\tText: \"object text\",\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "example/object-map-example/controller/controller.go",
    "content": "package controller\n\n// Controller example\ntype Controller struct {\n}\n\n// NewController example\nfunc NewController() *Controller {\n\treturn &Controller{}\n}\n"
  },
  {
    "path": "example/object-map-example/controller/response.go",
    "content": "package controller\n\ntype Response struct {\n\tTitle      map[string]string      `json:\"title\" example:\"en:Map,ru:Карта,kk:Карталар\"`\n\tCustomType map[string]interface{} `json:\"map_data\" swaggertype:\"object,string\" example:\"key:value,key2:value2\"`\n\tObject     Data                   `json:\"object\"`\n}\n\ntype Data struct {\n\tText string `json:\"title\" example:\"Object data\"`\n}\n"
  },
  {
    "path": "example/object-map-example/docs/docs.go",
    "content": "// Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n// This file was generated by swaggo/swag\npackage docs\n\nimport \"github.com/swaggo/swag\"\n\nconst docTemplate = `{\n    \"schemes\": {{ marshal .Schemes }},\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"{{escape .Description}}\",\n        \"title\": \"{{.Title}}\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {},\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"{{.Version}}\"\n    },\n    \"host\": \"{{.Host}}\",\n    \"basePath\": \"{{.BasePath}}\",\n    \"paths\": {\n        \"/test\": {\n            \"get\": {\n                \"description\": \"get map\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Get Map Example\",\n                \"operationId\": \"get-map\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/controller.Response\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"controller.Data\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"title\": {\n                    \"type\": \"string\",\n                    \"example\": \"Object data\"\n                }\n            }\n        },\n        \"controller.Response\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"map_data\": {\n                    \"type\": \"object\",\n                    \"additionalProperties\": {\n                        \"type\": \"string\"\n                    },\n                    \"example\": {\n                        \"key\": \"value\",\n                        \"key2\": \"value2\"\n                    }\n                },\n                \"object\": {\n                    \"$ref\": \"#/definitions/controller.Data\"\n                },\n                \"title\": {\n                    \"type\": \"object\",\n                    \"additionalProperties\": {\n                        \"type\": \"string\"\n                    },\n                    \"example\": {\n                        \"en\": \"Map\",\n                        \"kk\": \"Карталар\",\n                        \"ru\": \"Карта\"\n                    }\n                }\n            }\n        }\n    }\n}`\n\n// SwaggerInfo holds exported Swagger Info so clients can modify it\nvar SwaggerInfo = &swag.Spec{\n\tVersion:          \"1.0\",\n\tHost:             \"localhost:8080\",\n\tBasePath:         \"/api/v1\",\n\tSchemes:          []string{},\n\tTitle:            \"Swagger Map Example API\",\n\tDescription:      \"\",\n\tInfoInstanceName: \"swagger\",\n\tSwaggerTemplate:  docTemplate,\n}\n\nfunc init() {\n\tswag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)\n}\n"
  },
  {
    "path": "example/object-map-example/docs/swagger.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"title\": \"Swagger Map Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {},\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:8080\",\n    \"basePath\": \"/api/v1\",\n    \"paths\": {\n        \"/test\": {\n            \"get\": {\n                \"description\": \"get map\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Get Map Example\",\n                \"operationId\": \"get-map\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/controller.Response\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"controller.Data\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"title\": {\n                    \"type\": \"string\",\n                    \"example\": \"Object data\"\n                }\n            }\n        },\n        \"controller.Response\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"map_data\": {\n                    \"type\": \"object\",\n                    \"additionalProperties\": {\n                        \"type\": \"string\"\n                    },\n                    \"example\": {\n                        \"key\": \"value\",\n                        \"key2\": \"value2\"\n                    }\n                },\n                \"object\": {\n                    \"$ref\": \"#/definitions/controller.Data\"\n                },\n                \"title\": {\n                    \"type\": \"object\",\n                    \"additionalProperties\": {\n                        \"type\": \"string\"\n                    },\n                    \"example\": {\n                        \"en\": \"Map\",\n                        \"kk\": \"Карталар\",\n                        \"ru\": \"Карта\"\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "example/object-map-example/docs/swagger.yaml",
    "content": "basePath: /api/v1\ndefinitions:\n  controller.Data:\n    properties:\n      title:\n        example: Object data\n        type: string\n    type: object\n  controller.Response:\n    properties:\n      map_data:\n        additionalProperties:\n          type: string\n        example:\n          key: value\n          key2: value2\n        type: object\n      object:\n        $ref: '#/definitions/controller.Data'\n      title:\n        additionalProperties:\n          type: string\n        example:\n          en: Map\n          kk: Карталар\n          ru: Карта\n        type: object\n    type: object\nhost: localhost:8080\ninfo:\n  contact: {}\n  license:\n    name: Apache 2.0\n    url: http://www.apache.org/licenses/LICENSE-2.0.html\n  termsOfService: http://swagger.io/terms/\n  title: Swagger Map Example API\n  version: \"1.0\"\npaths:\n  /test:\n    get:\n      consumes:\n      - application/json\n      description: get map\n      operationId: get-map\n      produces:\n      - application/json\n      responses:\n        \"200\":\n          description: OK\n          schema:\n            $ref: '#/definitions/controller.Response'\n      summary: Get Map Example\nswagger: \"2.0\"\n"
  },
  {
    "path": "example/object-map-example/go.mod",
    "content": "module github.com/swaggo/swag/example/object-map-example\n\ngo 1.24.0\n\nrequire (\n\tgithub.com/gin-gonic/gin v1.9.1\n\tgithub.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2\n\tgithub.com/swaggo/gin-swagger v1.4.2\n\tgithub.com/swaggo/swag v1.8.1\n)\n\nrequire (\n\tgithub.com/KyleBanks/depth v1.2.1 // indirect\n\tgithub.com/bytedance/sonic v1.9.1 // indirect\n\tgithub.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect\n\tgithub.com/gabriel-vasile/mimetype v1.4.2 // indirect\n\tgithub.com/gin-contrib/sse v0.1.0 // indirect\n\tgithub.com/go-openapi/jsonpointer v0.19.5 // indirect\n\tgithub.com/go-openapi/jsonreference v0.20.0 // indirect\n\tgithub.com/go-openapi/spec v0.20.5 // indirect\n\tgithub.com/go-openapi/swag v0.19.15 // indirect\n\tgithub.com/go-playground/locales v0.14.1 // indirect\n\tgithub.com/go-playground/universal-translator v0.18.1 // indirect\n\tgithub.com/go-playground/validator/v10 v10.14.0 // indirect\n\tgithub.com/goccy/go-json v0.10.2 // indirect\n\tgithub.com/josharian/intern v1.0.0 // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/klauspost/cpuid/v2 v2.2.4 // indirect\n\tgithub.com/leodido/go-urn v1.2.4 // indirect\n\tgithub.com/mailru/easyjson v0.7.6 // indirect\n\tgithub.com/mattn/go-isatty v0.0.19 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.2 // indirect\n\tgithub.com/pelletier/go-toml/v2 v2.0.8 // indirect\n\tgithub.com/twitchyliquid64/golang-asm v0.15.1 // indirect\n\tgithub.com/ugorji/go/codec v1.2.11 // indirect\n\tgolang.org/x/arch v0.3.0 // indirect\n\tgolang.org/x/crypto v0.45.0 // indirect\n\tgolang.org/x/net v0.47.0 // indirect\n\tgolang.org/x/sys v0.38.0 // indirect\n\tgolang.org/x/text v0.31.0 // indirect\n\tgolang.org/x/tools v0.38.0 // indirect\n\tgoogle.golang.org/protobuf v1.33.0 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "example/object-map-example/go.sum",
    "content": "github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=\ngithub.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=\ngithub.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=\ngithub.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=\ngithub.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=\ngithub.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=\ngithub.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=\ngithub.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=\ngithub.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=\ngithub.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=\ngithub.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=\ngithub.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=\ngithub.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/gin-contrib/gzip v0.0.3 h1:etUaeesHhEORpZMp18zoOhepboiWnFtXrBZxszWUn4k=\ngithub.com/gin-contrib/gzip v0.0.3/go.mod h1:YxxswVZIqOvcHEQpsSn+QF5guQtO1dCfy0shBPy4jFc=\ngithub.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=\ngithub.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=\ngithub.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=\ngithub.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=\ngithub.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=\ngithub.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=\ngithub.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=\ngithub.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=\ngithub.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=\ngithub.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=\ngithub.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=\ngithub.com/go-openapi/spec v0.20.5 h1:skHa8av4VnAtJU5zyAUXrrdK/NDiVX8lchbG+BfcdrE=\ngithub.com/go-openapi/spec v0.20.5/go.mod h1:QbfOSIVt3/sac+a1wzmKbbcLXm5NdZnyBZYtCijp43o=\ngithub.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=\ngithub.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=\ngithub.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=\ngithub.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=\ngithub.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=\ngithub.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=\ngithub.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=\ngithub.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=\ngithub.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=\ngithub.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=\ngithub.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=\ngithub.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=\ngithub.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=\ngithub.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=\ngithub.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=\ngithub.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=\ngithub.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=\ngithub.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=\ngithub.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=\ngithub.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=\ngithub.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=\ngithub.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=\ngithub.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=\ngithub.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=\ngithub.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=\ngithub.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=\ngithub.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=\ngithub.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=\ngithub.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=\ngithub.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=\ngithub.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=\ngithub.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=\ngithub.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=\ngithub.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 h1:+iNTcqQJy0OZ5jk6a5NLib47eqXK8uYcPX+O4+cBpEM=\ngithub.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=\ngithub.com/swaggo/gin-swagger v1.4.2 h1:qDs1YrBOTnurDG/JVMc8678KhoS1B1okQGPtIqVz4YU=\ngithub.com/swaggo/gin-swagger v1.4.2/go.mod h1:hmJ1vPn+XjUvnbzjCdUAxVqgraxELxk8x5zAsjCE5mg=\ngithub.com/swaggo/swag v1.7.9/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=\ngithub.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI=\ngithub.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=\ngithub.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=\ngithub.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=\ngithub.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=\ngithub.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=\ngithub.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=\ngithub.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=\ngithub.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=\ngithub.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngolang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=\ngolang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=\ngolang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=\ngolang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=\ngolang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=\ngolang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=\ngolang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=\ngolang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=\ngolang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=\ngolang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=\ngolang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=\ngolang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=\ngoogle.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nrsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=\n"
  },
  {
    "path": "example/object-map-example/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/swaggo/swag/example/object-map-example/controller\"\n\t_ \"github.com/swaggo/swag/example/object-map-example/docs\"\n\n\tswaggerFiles \"github.com/swaggo/files\"\n\tginSwagger \"github.com/swaggo/gin-swagger\"\n)\n\n//\t@title\t\t\tSwagger Map Example API\n//\t@version\t\t1.0\n//\t@termsOfService\thttp://swagger.io/terms/\n\n//\t@license.name\tApache 2.0\n//\t@license.url\thttp://www.apache.org/licenses/LICENSE-2.0.html\n\n//\t@host\t\tlocalhost:8080\n//\t@BasePath\t/api/v1\n\nfunc main() {\n\tr := gin.Default()\n\n\tc := controller.NewController()\n\n\tv1 := r.Group(\"/api/v1\")\n\t{\n\t\ttest := v1.Group(\"/map\")\n\t\t{\n\t\t\ttest.GET(\"\", c.GetMap)\n\t\t}\n\t}\n\tr.GET(\"/swagger/*any\", ginSwagger.WrapHandler(swaggerFiles.Handler))\n\tr.Run(\":8080\")\n}\n"
  },
  {
    "path": "example/override/.swaggo",
    "content": "replace sql.NullString string\nreplace sql.NullInt64 int64\n"
  },
  {
    "path": "example/override/docs/docs.go",
    "content": "// Package docs GENERATED BY SWAG; DO NOT EDIT\n// This file was generated by swaggo/swag\npackage docs\n\nimport \"github.com/swaggo/swag\"\n\nconst docTemplate = `{\n    \"schemes\": {{ marshal .Schemes }},\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"{{escape .Description}}\",\n        \"title\": \"{{.Title}}\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"{{.Version}}\"\n    },\n    \"host\": \"{{.Host}}\",\n    \"basePath\": \"{{.BasePath}}\",\n    \"paths\": {\n        \"/testapi/update-product/{product_id}\": {\n            \"post\": {\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Update product attributes\",\n                \"operationId\": \"update-product\",\n                \"parameters\": [\n                    {\n                        \"type\": \"integer\",\n                        \"description\": \"Product ID\",\n                        \"name\": \"product_id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    },\n                    {\n                        \"description\": \" \",\n                        \"name\": \"_\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/main.ProductUpdates\"\n                        }\n                    }\n                ],\n                \"responses\": {}\n            }\n        }\n    },\n    \"definitions\": {\n        \"main.ProductUpdates\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"description\": {\n                    \"type\": \"string\"\n                },\n                \"stock\": {\n                    \"type\": \"integer\"\n                },\n                \"type\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}`\n\n// SwaggerInfo holds exported Swagger Info so clients can modify it\nvar SwaggerInfo = &swag.Spec{\n\tVersion:          \"1.0\",\n\tHost:             \"product_info.swagger.io\",\n\tBasePath:         \"/v2\",\n\tSchemes:          []string{},\n\tTitle:            \"Swagger Example API\",\n\tDescription:      \"This is a sample server for updating product information.\",\n\tInfoInstanceName: \"swagger\",\n\tSwaggerTemplate:  docTemplate,\n}\n\nfunc init() {\n\tswag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)\n}\n"
  },
  {
    "path": "example/override/docs/swagger.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server for updating product information.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"product_info.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {\n        \"/testapi/update-product/{product_id}\": {\n            \"post\": {\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Update product attributes\",\n                \"operationId\": \"update-product\",\n                \"parameters\": [\n                    {\n                        \"type\": \"integer\",\n                        \"description\": \"Product ID\",\n                        \"name\": \"product_id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    },\n                    {\n                        \"description\": \" \",\n                        \"name\": \"_\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/main.ProductUpdates\"\n                        }\n                    }\n                ],\n                \"responses\": {}\n            }\n        }\n    },\n    \"definitions\": {\n        \"main.ProductUpdates\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"description\": {\n                    \"type\": \"string\"\n                },\n                \"stock\": {\n                    \"type\": \"integer\"\n                },\n                \"type\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "example/override/docs/swagger.yaml",
    "content": "basePath: /v2\ndefinitions:\n  main.ProductUpdates:\n    properties:\n      description:\n        type: string\n      stock:\n        type: integer\n      type:\n        type: string\n    type: object\nhost: product_info.swagger.io\ninfo:\n  contact:\n    email: support@swagger.io\n    name: API Support\n    url: http://www.swagger.io/support\n  description: This is a sample server for updating product information.\n  license:\n    name: Apache 2.0\n    url: http://www.apache.org/licenses/LICENSE-2.0.html\n  termsOfService: http://swagger.io/terms/\n  title: Swagger Example API\n  version: \"1.0\"\npaths:\n  /testapi/update-product/{product_id}:\n    post:\n      consumes:\n      - application/json\n      operationId: update-product\n      parameters:\n      - description: Product ID\n        in: path\n        name: product_id\n        required: true\n        type: integer\n      - description: ' '\n        in: body\n        name: _\n        required: true\n        schema:\n          $ref: '#/definitions/main.ProductUpdates'\n      responses: {}\n      summary: Update product attributes\nswagger: \"2.0\"\n"
  },
  {
    "path": "example/override/handler.go",
    "content": "package main\n\nimport (\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\ntype ProductUpdates struct {\n\tType        sql.NullString `json:\"type\"`\n\tDescription sql.NullString `json:\"description\"`\n\tStock       sql.NullInt64  `json:\"stock\"`\n}\n\n// UpdateProduct example\n//\n//\t@Summary\tUpdate product attributes\n//\t@ID\t\t\tupdate-product\n//\t@Accept\t\tjson\n//\t@Param\t\tproduct_id\tpath\tint\t\t\t\ttrue\t\"Product ID\"\n//\t@Param\t\t_\t\t\tbody\tProductUpdates\ttrue\t\" \"\n//\t@Router\t\t/testapi/update-product/{product_id} [post]\nfunc UpdateProduct(w http.ResponseWriter, r *http.Request) {\n\tvar pUpdates ProductUpdates\n\tif err := json.NewDecoder(r.Body).Decode(&pUpdates); err != nil {\n\t\t// write your code\n\t\treturn\n\t}\n\n\t// write your code\n}\n"
  },
  {
    "path": "example/override/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n)\n\n//\t@title\t\t\tSwagger Example API\n//\t@version\t\t1.0\n//\t@description\tThis is a sample server with null types overridden with primitive types.\n//\t@termsOfService\thttp://swagger.io/terms/\n\n//\t@contact.name\tAPI Support\n//\t@contact.url\thttp://www.swagger.io/support\n//\t@contact.email\tsupport@swagger.io\n\n//\t@license.name\tApache 2.0\n//\t@license.url\thttp://www.apache.org/licenses/LICENSE-2.0.html\n\n//\t@host\t\tproduct_info.swagger.io\n//\t@BasePath\t/v2\n\nfunc main() {\n\thttp.HandleFunc(\"/testapi/update-product\", UpdateProduct)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "field_parser.go",
    "content": "package swag\n\nimport (\n\t\"fmt\"\n\t\"go/ast\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"unicode\"\n\n\t\"github.com/go-openapi/spec\"\n)\n\nvar _ FieldParser = &tagBaseFieldParser{p: nil, field: nil, tag: \"\"}\n\nconst (\n\trequiredLabel    = \"required\"\n\toptionalLabel    = \"optional\"\n\tomitEmptyLabel   = \"omitempty\"\n\tswaggerTypeTag   = \"swaggertype\"\n\tswaggerIgnoreTag = \"swaggerignore\"\n)\n\ntype tagBaseFieldParser struct {\n\tp     *Parser\n\tfield *ast.Field\n\ttag   reflect.StructTag\n}\n\nfunc newTagBaseFieldParser(p *Parser, field *ast.Field) FieldParser {\n\tfieldParser := tagBaseFieldParser{\n\t\tp:     p,\n\t\tfield: field,\n\t\ttag:   \"\",\n\t}\n\tif fieldParser.field.Tag != nil {\n\t\tfieldParser.tag = reflect.StructTag(strings.ReplaceAll(field.Tag.Value, \"`\", \"\"))\n\t}\n\n\treturn &fieldParser\n}\n\nfunc (ps *tagBaseFieldParser) ShouldSkip() bool {\n\t// Skip non-exported fields.\n\tif ps.field.Names != nil && !ast.IsExported(ps.field.Names[0].Name) {\n\t\treturn true\n\t}\n\n\tif ps.field.Tag == nil {\n\t\treturn false\n\t}\n\n\tignoreTag := ps.tag.Get(swaggerIgnoreTag)\n\tif strings.EqualFold(ignoreTag, \"true\") {\n\t\treturn true\n\t}\n\n\t// json:\"tag,hoge\"\n\tname := strings.TrimSpace(strings.Split(ps.tag.Get(jsonTag), \",\")[0])\n\tif name == \"-\" {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (ps *tagBaseFieldParser) FieldNames() ([]string, error) {\n\tif len(ps.field.Names) <= 1 {\n\t\t// if embedded but with a json/form name ??\n\t\tif ps.field.Tag != nil {\n\t\t\t// json:\"tag,hoge\"\n\t\t\tname := strings.TrimSpace(strings.Split(ps.tag.Get(jsonTag), \",\")[0])\n\t\t\tif name != \"\" {\n\t\t\t\treturn []string{name}, nil\n\t\t\t}\n\n\t\t\t// use \"form\" tag over json tag\n\t\t\tname = ps.FormName()\n\t\t\tif name != \"\" {\n\t\t\t\treturn []string{name}, nil\n\t\t\t}\n\t\t}\n\t\tif len(ps.field.Names) == 0 {\n\t\t\treturn nil, nil\n\t\t}\n\t}\n\tvar names = make([]string, 0, len(ps.field.Names))\n\tfor _, name := range ps.field.Names {\n\t\tswitch ps.p.PropNamingStrategy {\n\t\tcase SnakeCase:\n\t\t\tnames = append(names, toSnakeCase(name.Name))\n\t\tcase PascalCase:\n\t\t\tnames = append(names, name.Name)\n\t\tdefault:\n\t\t\tnames = append(names, toLowerCamelCase(name.Name))\n\t\t}\n\t}\n\treturn names, nil\n}\n\nfunc (ps *tagBaseFieldParser) FirstTagValue(tag string) string {\n\tif ps.field.Tag != nil {\n\t\treturn strings.TrimRight(strings.TrimSpace(strings.Split(ps.tag.Get(tag), \",\")[0]), \"[]\")\n\t}\n\treturn \"\"\n}\n\nfunc (ps *tagBaseFieldParser) FormName() string {\n\treturn ps.FirstTagValue(formTag)\n}\n\nfunc (ps *tagBaseFieldParser) QueryName() string {\n\treturn ps.FirstTagValue(queryTag)\n}\n\nfunc (ps *tagBaseFieldParser) HeaderName() string {\n\treturn ps.FirstTagValue(headerTag)\n}\n\nfunc (ps *tagBaseFieldParser) PathName() string {\n\treturn ps.FirstTagValue(uriTag)\n}\n\nfunc (ps *tagBaseFieldParser) ParamName() string {\n\treturn ps.FirstTagValue(paramTag)\n}\n\nfunc toSnakeCase(in string) string {\n\tvar (\n\t\trunes  = []rune(in)\n\t\tlength = len(runes)\n\t\tout    []rune\n\t)\n\n\tfor idx := 0; idx < length; idx++ {\n\t\tif idx > 0 && unicode.IsUpper(runes[idx]) &&\n\t\t\t((idx+1 < length && unicode.IsLower(runes[idx+1])) || unicode.IsLower(runes[idx-1])) {\n\t\t\tout = append(out, '_')\n\t\t}\n\n\t\tout = append(out, unicode.ToLower(runes[idx]))\n\t}\n\n\treturn string(out)\n}\n\nfunc toLowerCamelCase(in string) string {\n\tvar flag bool\n\n\tout := make([]rune, len(in))\n\n\trunes := []rune(in)\n\tfor i, curr := range runes {\n\t\tif (i == 0 && unicode.IsUpper(curr)) || (flag && unicode.IsUpper(curr)) {\n\t\t\tout[i] = unicode.ToLower(curr)\n\t\t\tflag = true\n\n\t\t\tcontinue\n\t\t}\n\n\t\tout[i] = curr\n\t\tflag = false\n\t}\n\n\treturn string(out)\n}\n\nfunc (ps *tagBaseFieldParser) CustomSchema() (*spec.Schema, error) {\n\tif ps.field.Tag == nil {\n\t\treturn nil, nil\n\t}\n\n\ttypeTag := ps.tag.Get(swaggerTypeTag)\n\tif typeTag != \"\" {\n\t\treturn BuildCustomSchema(strings.Split(typeTag, \",\"))\n\t}\n\n\treturn nil, nil\n}\n\ntype structField struct {\n\ttitle        string\n\tschemaType   string\n\tarrayType    string\n\tformatType   string\n\tmaximum      *float64\n\tminimum      *float64\n\tmultipleOf   *float64\n\tmaxLength    *int64\n\tminLength    *int64\n\tmaxItems     *int64\n\tminItems     *int64\n\texampleValue any\n\tenums        []any\n\tenumVarNames []any\n\tunique       bool\n}\n\n// splitNotWrapped slices s into all substrings separated by sep if sep is not\n// wrapped by brackets and returns a slice of the substrings between those separators.\nfunc splitNotWrapped(s string, sep rune) []string {\n\topenCloseMap := map[rune]rune{\n\t\t'(': ')',\n\t\t'[': ']',\n\t\t'{': '}',\n\t}\n\n\tvar (\n\t\tresult    = make([]string, 0)\n\t\tcurrent   = strings.Builder{}\n\t\topenCount = 0\n\t\topenChar  rune\n\t)\n\n\tfor _, char := range s {\n\t\tswitch {\n\t\tcase openChar == 0 && openCloseMap[char] != 0:\n\t\t\topenChar = char\n\n\t\t\topenCount++\n\n\t\t\tcurrent.WriteRune(char)\n\t\tcase char == openChar:\n\t\t\topenCount++\n\n\t\t\tcurrent.WriteRune(char)\n\t\tcase openCount > 0 && char == openCloseMap[openChar]:\n\t\t\topenCount--\n\n\t\t\tcurrent.WriteRune(char)\n\t\tcase openCount == 0 && char == sep:\n\t\t\tresult = append(result, current.String())\n\n\t\t\topenChar = 0\n\n\t\t\tcurrent = strings.Builder{}\n\t\tdefault:\n\t\t\tcurrent.WriteRune(char)\n\t\t}\n\t}\n\n\tif current.String() != \"\" {\n\t\tresult = append(result, current.String())\n\t}\n\n\treturn result\n}\n\n// ComplementSchema complement schema with field properties\nfunc (ps *tagBaseFieldParser) ComplementSchema(schema *spec.Schema) error {\n\ttypes := ps.p.GetSchemaTypePath(schema, 2)\n\tif len(types) == 0 {\n\t\treturn fmt.Errorf(\"invalid type for field: %s\", ps.field.Names[0])\n\t}\n\n\tif IsRefSchema(schema) {\n\t\tvar newSchema = spec.Schema{}\n\t\terr := ps.complementSchema(&newSchema, types)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif !reflect.ValueOf(newSchema).IsZero() {\n\t\t\t*schema = *(newSchema.WithAllOf(*schema))\n\t\t}\n\t\treturn nil\n\t}\n\n\treturn ps.complementSchema(schema, types)\n}\n\n// complementSchema complement schema with field properties\nfunc (ps *tagBaseFieldParser) complementSchema(schema *spec.Schema, types []string) error {\n\tif ps.field.Tag == nil {\n\t\tif ps.field.Doc != nil {\n\t\t\tschema.Description = strings.TrimSpace(ps.field.Doc.Text())\n\t\t}\n\n\t\tif schema.Description == \"\" && ps.field.Comment != nil {\n\t\t\tschema.Description = strings.TrimSpace(ps.field.Comment.Text())\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tfield := &structField{\n\t\tschemaType: types[0],\n\t\tformatType: ps.tag.Get(formatTag),\n\t\ttitle:      ps.tag.Get(titleTag),\n\t}\n\n\tif len(types) > 1 && (types[0] == ARRAY || types[0] == OBJECT) {\n\t\tfield.arrayType = types[1]\n\t}\n\n\tjsonTagValue := ps.tag.Get(jsonTag)\n\n\tbindingTagValue := ps.tag.Get(bindingTag)\n\tif bindingTagValue != \"\" {\n\t\tparseValidTags(bindingTagValue, field)\n\t}\n\n\tvalidateTagValue := ps.tag.Get(validateTag)\n\tif validateTagValue != \"\" {\n\t\tparseValidTags(validateTagValue, field)\n\t}\n\n\tenumsTagValue := ps.tag.Get(enumsTag)\n\tif enumsTagValue != \"\" {\n\t\terr := parseEnumTags(enumsTagValue, field)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif IsNumericType(field.schemaType) || IsNumericType(field.arrayType) {\n\t\tmaximum, err := getFloatTag(ps.tag, maximumTag)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif maximum != nil {\n\t\t\tfield.maximum = maximum\n\t\t}\n\n\t\tminimum, err := getFloatTag(ps.tag, minimumTag)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif minimum != nil {\n\t\t\tfield.minimum = minimum\n\t\t}\n\n\t\tmultipleOf, err := getFloatTag(ps.tag, multipleOfTag)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif multipleOf != nil {\n\t\t\tfield.multipleOf = multipleOf\n\t\t}\n\t}\n\n\tif field.schemaType == STRING || field.arrayType == STRING {\n\t\tmaxLength, err := getIntTag(ps.tag, maxLengthTag)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif maxLength != nil {\n\t\t\tfield.maxLength = maxLength\n\t\t}\n\n\t\tminLength, err := getIntTag(ps.tag, minLengthTag)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif minLength != nil {\n\t\t\tfield.minLength = minLength\n\t\t}\n\t}\n\n\t// json:\"name,string\" or json:\",string\"\n\texampleTagValue, ok := ps.tag.Lookup(exampleTag)\n\tif ok {\n\t\tfield.exampleValue = exampleTagValue\n\n\t\tif !strings.Contains(jsonTagValue, \",string\") {\n\t\t\texample, err := defineTypeOfExample(field.schemaType, field.arrayType, exampleTagValue)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfield.exampleValue = example\n\t\t}\n\t}\n\n\t// perform this after setting everything else (min, max, etc...)\n\tif strings.Contains(jsonTagValue, \",string\") {\n\t\t// @encoding/json: \"It applies only to fields of string, floating point, integer, or boolean types.\"\n\t\tdefaultValues := map[string]string{\n\t\t\t// Zero Values as string\n\t\t\tSTRING:  \"\",\n\t\t\tINTEGER: \"0\",\n\t\t\tBOOLEAN: \"false\",\n\t\t\tNUMBER:  \"0\",\n\t\t}\n\n\t\tdefaultValue, ok := defaultValues[field.schemaType]\n\t\tif ok {\n\t\t\tfield.schemaType = STRING\n\t\t\t*schema = *PrimitiveSchema(field.schemaType)\n\n\t\t\tif field.exampleValue == nil {\n\t\t\t\t// if exampleValue is not defined by the user,\n\t\t\t\t// we will force an example with a correct value\n\t\t\t\t// (eg: int->\"0\", bool:\"false\")\n\t\t\t\tfield.exampleValue = defaultValue\n\t\t\t}\n\t\t}\n\t}\n\n\tif ps.field.Doc != nil {\n\t\tschema.Description = strings.TrimSpace(ps.field.Doc.Text())\n\t}\n\n\tif schema.Description == \"\" && ps.field.Comment != nil {\n\t\tschema.Description = strings.TrimSpace(ps.field.Comment.Text())\n\t}\n\n\tschema.ReadOnly = ps.tag.Get(readOnlyTag) == \"true\"\n\n\tdefaultTagValue, ok := ps.tag.Lookup(defaultTag)\n\tif ok {\n\t\tvalue, err := defineType(field.schemaType, defaultTagValue)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tschema.Default = value\n\t}\n\n\tschema.Example = field.exampleValue\n\n\tif field.schemaType != ARRAY {\n\t\tschema.Format = field.formatType\n\t}\n\tschema.Title = field.title\n\n\textensionsTagValue := ps.tag.Get(extensionsTag)\n\tif extensionsTagValue != \"\" {\n\t\tschema.Extensions = setExtensionParam(extensionsTagValue)\n\t}\n\n\tvarNamesTag := ps.tag.Get(\"x-enum-varnames\")\n\tif varNamesTag != \"\" {\n\t\tvarNames := strings.Split(varNamesTag, \",\")\n\t\tif len(varNames) != len(field.enums) {\n\t\t\treturn fmt.Errorf(\"invalid count of x-enum-varnames. expected %d, got %d\", len(field.enums), len(varNames))\n\t\t}\n\n\t\tfield.enumVarNames = nil\n\n\t\tfor _, v := range varNames {\n\t\t\tfield.enumVarNames = append(field.enumVarNames, v)\n\t\t}\n\n\t\tif field.schemaType == ARRAY {\n\t\t\t// Add the var names in the items schema\n\t\t\tif schema.Items.Schema.Extensions == nil {\n\t\t\t\tschema.Items.Schema.Extensions = map[string]any{}\n\t\t\t}\n\t\t\tschema.Items.Schema.Extensions[enumVarNamesExtension] = field.enumVarNames\n\t\t} else {\n\t\t\t// Add to top level schema\n\t\t\tif schema.Extensions == nil {\n\t\t\t\tschema.Extensions = map[string]any{}\n\t\t\t}\n\t\t\tschema.Extensions[enumVarNamesExtension] = field.enumVarNames\n\t\t}\n\t}\n\n\teleSchema := schema\n\n\tif field.schemaType == ARRAY {\n\t\t// For Array only\n\t\tschema.MaxItems = field.maxItems\n\t\tschema.MinItems = field.minItems\n\t\tschema.UniqueItems = field.unique\n\n\t\tif schema.Items != nil {\n\t\t\teleSchema = schema.Items.Schema\n\t\t}\n\n\t\teleSchema.Format = field.formatType\n\t}\n\n\teleSchema.Maximum = field.maximum\n\teleSchema.Minimum = field.minimum\n\teleSchema.MultipleOf = field.multipleOf\n\teleSchema.MaxLength = field.maxLength\n\teleSchema.MinLength = field.minLength\n\teleSchema.Enum = field.enums\n\n\treturn nil\n}\n\nfunc getFloatTag(structTag reflect.StructTag, tagName string) (*float64, error) {\n\tstrValue := structTag.Get(tagName)\n\tif strValue == \"\" {\n\t\treturn nil, nil\n\t}\n\n\tvalue, err := strconv.ParseFloat(strValue, 64)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"can't parse numeric value of %q tag: %v\", tagName, err)\n\t}\n\n\treturn &value, nil\n}\n\nfunc getIntTag(structTag reflect.StructTag, tagName string) (*int64, error) {\n\tstrValue := structTag.Get(tagName)\n\tif strValue == \"\" {\n\t\treturn nil, nil\n\t}\n\n\tvalue, err := strconv.ParseInt(strValue, 10, 64)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"can't parse numeric value of %q tag: %v\", tagName, err)\n\t}\n\n\treturn &value, nil\n}\n\nfunc (ps *tagBaseFieldParser) IsRequired() (bool, error) {\n\tif ps.field.Tag == nil {\n\t\treturn false, nil\n\t}\n\n\tbindingTag := ps.tag.Get(bindingTag)\n\tif bindingTag != \"\" {\n\t\tfor _, val := range strings.Split(bindingTag, \",\") {\n\t\t\tswitch val {\n\t\t\tcase requiredLabel:\n\t\t\t\treturn true, nil\n\t\t\tcase optionalLabel:\n\t\t\t\treturn false, nil\n\t\t\t}\n\t\t}\n\t}\n\n\tvalidateTag := ps.tag.Get(validateTag)\n\tif validateTag != \"\" {\n\t\tfor _, val := range strings.Split(validateTag, \",\") {\n\t\t\tswitch val {\n\t\t\tcase requiredLabel:\n\t\t\t\treturn true, nil\n\t\t\tcase optionalLabel:\n\t\t\t\treturn false, nil\n\t\t\t}\n\t\t}\n\t}\n\n\tjsonTag := ps.tag.Get(jsonTag)\n\tif jsonTag != \"\" {\n\t\tfor _, val := range strings.Split(jsonTag, \",\") {\n\t\t\tif val == omitEmptyLabel {\n\t\t\t\treturn false, nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ps.p.RequiredByDefault, nil\n}\n\nfunc parseValidTags(validTag string, sf *structField) {\n\t// `validate:\"required,max=10,min=1\"`\n\t// ps. required checked by IsRequired().\n\tfor _, val := range strings.Split(validTag, \",\") {\n\t\tvar (\n\t\t\tvalValue string\n\t\t\tkeyVal   = strings.Split(val, \"=\")\n\t\t)\n\n\t\tswitch len(keyVal) {\n\t\tcase 1:\n\t\tcase 2:\n\t\t\tvalValue = strings.ReplaceAll(strings.ReplaceAll(keyVal[1], utf8HexComma, \",\"), utf8Pipe, \"|\")\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch keyVal[0] {\n\t\tcase \"max\", \"lte\":\n\t\t\tsf.setMax(valValue)\n\t\tcase \"min\", \"gte\":\n\t\t\tsf.setMin(valValue)\n\t\tcase \"oneof\":\n\t\t\tsf.setOneOf(valValue)\n\t\tcase \"unique\":\n\t\t\tif sf.schemaType == ARRAY {\n\t\t\t\tsf.unique = true\n\t\t\t}\n\t\tcase \"dive\":\n\t\t\t// ignore dive\n\t\t\treturn\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t}\n}\n\nfunc parseEnumTags(enumTag string, field *structField) error {\n\tenumType := field.schemaType\n\tif field.schemaType == ARRAY {\n\t\tenumType = field.arrayType\n\t}\n\n\tfield.enums = nil\n\n\tfor _, e := range strings.Split(enumTag, \",\") {\n\t\tvalue, err := defineType(enumType, e)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfield.enums = append(field.enums, value)\n\t}\n\n\treturn nil\n}\n\nfunc (sf *structField) setOneOf(valValue string) {\n\tif len(sf.enums) != 0 {\n\t\treturn\n\t}\n\n\tenumType := sf.schemaType\n\tif sf.schemaType == ARRAY {\n\t\tenumType = sf.arrayType\n\t}\n\n\tvalValues := parseOneOfParam2(valValue)\n\tfor i := range valValues {\n\t\tvalue, err := defineType(enumType, valValues[i])\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tsf.enums = append(sf.enums, value)\n\t}\n}\n\nfunc (sf *structField) setMin(valValue string) {\n\tvalue, err := strconv.ParseFloat(valValue, 64)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tswitch sf.schemaType {\n\tcase INTEGER, NUMBER:\n\t\tsf.minimum = &value\n\tcase STRING:\n\t\tintValue := int64(value)\n\t\tsf.minLength = &intValue\n\tcase ARRAY:\n\t\tintValue := int64(value)\n\t\tsf.minItems = &intValue\n\t}\n}\n\nfunc (sf *structField) setMax(valValue string) {\n\tvalue, err := strconv.ParseFloat(valValue, 64)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tswitch sf.schemaType {\n\tcase INTEGER, NUMBER:\n\t\tsf.maximum = &value\n\tcase STRING:\n\t\tintValue := int64(value)\n\t\tsf.maxLength = &intValue\n\tcase ARRAY:\n\t\tintValue := int64(value)\n\t\tsf.maxItems = &intValue\n\t}\n}\n\nconst (\n\tutf8HexComma = \"0x2C\"\n\tutf8Pipe     = \"0x7C\"\n)\n\n// These code copy from\n// https://github.com/go-playground/validator/blob/d4271985b44b735c6f76abc7a06532ee997f9476/baked_in.go#L207\n// ---.\nvar oneofValsCache = map[string][]string{}\nvar oneofValsCacheRWLock = sync.RWMutex{}\nvar splitParamsRegex = regexp.MustCompile(`'[^']*'|\\S+`)\n\nfunc parseOneOfParam2(param string) []string {\n\toneofValsCacheRWLock.RLock()\n\tvalues, ok := oneofValsCache[param]\n\toneofValsCacheRWLock.RUnlock()\n\n\tif !ok {\n\t\toneofValsCacheRWLock.Lock()\n\t\tvalues = splitParamsRegex.FindAllString(param, -1)\n\n\t\tfor i := 0; i < len(values); i++ {\n\t\t\tvalues[i] = strings.ReplaceAll(values[i], \"'\", \"\")\n\t\t}\n\n\t\toneofValsCache[param] = values\n\n\t\toneofValsCacheRWLock.Unlock()\n\t}\n\n\treturn values\n}\n\n// ---.\n"
  },
  {
    "path": "field_parser_test.go",
    "content": "package swag\n\nimport (\n\t\"go/ast\"\n\t\"testing\"\n\n\t\"github.com/go-openapi/spec\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestDefaultFieldParser(t *testing.T) {\n\tt.Run(\"Example tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" example:\"one\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"one\", schema.Example)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" example:\"\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"\", schema.Example)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"float\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" example:\"one\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"Format tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" format:\"csv\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"csv\", schema.Format)\n\t})\n\n\tt.Run(\"Title tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" title:\"myfield\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"myfield\", schema.Title)\n\t})\n\n\tt.Run(\"Required tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tgot, err := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" binding:\"required\"`,\n\t\t\t}},\n\t\t).IsRequired()\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, true, got)\n\n\t\tgot, err = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required\"`,\n\t\t\t}},\n\t\t).IsRequired()\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, true, got)\n\t})\n\n\tt.Run(\"Default required tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tgot, err := newTagBaseFieldParser(\n\t\t\t&Parser{\n\t\t\t\tRequiredByDefault: true,\n\t\t\t},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\"`,\n\t\t\t}},\n\t\t).IsRequired()\n\t\tassert.NoError(t, err)\n\t\tassert.True(t, got)\n\t})\n\n\tt.Run(\"Optional tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tgot, err := newTagBaseFieldParser(\n\t\t\t&Parser{\n\t\t\t\tRequiredByDefault: true,\n\t\t\t},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" binding:\"optional\"`,\n\t\t\t}},\n\t\t).IsRequired()\n\t\tassert.NoError(t, err)\n\t\tassert.False(t, got)\n\n\t\tgot, err = newTagBaseFieldParser(\n\t\t\t&Parser{\n\t\t\t\tRequiredByDefault: true,\n\t\t\t},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"optional\"`,\n\t\t\t}},\n\t\t).IsRequired()\n\t\tassert.NoError(t, err)\n\t\tassert.False(t, got)\n\n\t\tgot, err = newTagBaseFieldParser(\n\t\t\t&Parser{\n\t\t\t\tRequiredByDefault: true,\n\t\t\t},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test,omitempty\"`,\n\t\t\t}},\n\t\t).IsRequired()\n\t\tassert.NoError(t, err)\n\t\tassert.False(t, got)\n\t})\n\n\tt.Run(\"Extensions tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"int\"}\n\t\tschema.Extensions = map[string]interface{}{}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" extensions:\"x-nullable,x-abc=def,!x-omitempty,x-example=[0, 9],x-example2={çãíœ, (bar=(abc, def)), [0,9]}\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, true, schema.Extensions[\"x-nullable\"])\n\t\tassert.Equal(t, \"def\", schema.Extensions[\"x-abc\"])\n\t\tassert.Equal(t, false, schema.Extensions[\"x-omitempty\"])\n\t\tassert.Equal(t, \"[0, 9]\", schema.Extensions[\"x-example\"])\n\t\tassert.Equal(t, \"{çãíœ, (bar=(abc, def)), [0,9]}\", schema.Extensions[\"x-example2\"])\n\t})\n\n\tt.Run(\"Enums tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" enums:\"a,b,c\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []interface{}{\"a\", \"b\", \"c\"}, schema.Enum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"float\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" enums:\"a,b,c\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"EnumVarNames tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"int\"}\n\t\tschema.Extensions = map[string]interface{}{}\n\t\tschema.Enum = []interface{}{}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" enums:\"0,1,2\" x-enum-varnames:\"Daily,Weekly,Monthly\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []interface{}{\"Daily\", \"Weekly\", \"Monthly\"}, schema.Extensions[\"x-enum-varnames\"])\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"int\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" enums:\"0,1,2,3\" x-enum-varnames:\"Daily,Weekly,Monthly\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.Error(t, err)\n\n\t\t// Test for an array of enums\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"array\"}\n\t\tschema.Items = &spec.SchemaOrArray{\n\t\t\tSchema: &spec.Schema{\n\t\t\t\tSchemaProps: spec.SchemaProps{\n\t\t\t\t\tType: []string{\"int\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tschema.Extensions = map[string]interface{}{}\n\t\tschema.Enum = []interface{}{}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" enums:\"0,1,2\" x-enum-varnames:\"Daily,Weekly,Monthly\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []interface{}{\"Daily\", \"Weekly\", \"Monthly\"}, schema.Items.Schema.Extensions[\"x-enum-varnames\"])\n\t\tassert.Equal(t, spec.Extensions{}, schema.Extensions)\n\t})\n\n\tt.Run(\"Default tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" default:\"pass\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"pass\", schema.Default)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"float\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" default:\"pass\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"Numeric value\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"integer\"}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" maximum:\"1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tmax := float64(1)\n\t\tassert.Equal(t, &max, schema.Maximum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"integer\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" maximum:\"one\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.Error(t, err)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"number\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" maximum:\"1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tmax = float64(1)\n\t\tassert.Equal(t, &max, schema.Maximum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"number\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" maximum:\"one\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.Error(t, err)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"number\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" multipleOf:\"1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tmultipleOf := float64(1)\n\t\tassert.Equal(t, &multipleOf, schema.MultipleOf)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"number\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" multipleOf:\"one\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.Error(t, err)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"integer\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" minimum:\"1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tmin := float64(1)\n\t\tassert.Equal(t, &min, schema.Minimum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"integer\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" minimum:\"one\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"String value\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" maxLength:\"1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tmax := int64(1)\n\t\tassert.Equal(t, &max, schema.MaxLength)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" maxLength:\"one\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.Error(t, err)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" minLength:\"1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tmin := int64(1)\n\t\tassert.Equal(t, &min, schema.MinLength)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" minLength:\"one\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"Readonly tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" readonly:\"true\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, true, schema.ReadOnly)\n\t})\n\n\tt.Run(\"Invalid tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Names: []*ast.Ident{{Name: \"BasicStruct\"}}},\n\t\t).ComplementSchema(nil)\n\t\tassert.Error(t, err)\n\t})\n}\n\nfunc TestValidTags(t *testing.T) {\n\tt.Run(\"Required with max/min tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,max=10,min=1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tmax := int64(10)\n\t\tmin := int64(1)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, &max, schema.MaxLength)\n\t\tassert.Equal(t, &min, schema.MinLength)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,max=10,gte=1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, &max, schema.MaxLength)\n\t\tassert.Equal(t, &min, schema.MinLength)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"integer\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,max=10,min=1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tmaxFloat64 := float64(10)\n\t\tminFloat64 := float64(1)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, &maxFloat64, schema.Maximum)\n\t\tassert.Equal(t, &minFloat64, schema.Minimum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"array\"}\n\t\tschema.Items = &spec.SchemaOrArray{\n\t\t\tSchema: &spec.Schema{\n\t\t\t\tSchemaProps: spec.SchemaProps{\n\t\t\t\t\tType: []string{\"string\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,max=10,min=1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, &max, schema.MaxItems)\n\t\tassert.Equal(t, &min, schema.MinItems)\n\n\t\t// wrong validate tag will be ignored.\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,max=ten,min=1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Empty(t, schema.MaxItems)\n\t\tassert.Equal(t, &min, schema.MinItems)\n\t})\n\tt.Run(\"Required with oneof tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,oneof='red book' 'green book'\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []interface{}{\"red book\", \"green book\"}, schema.Enum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"integer\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,oneof=1 2 3\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []interface{}{1, 2, 3}, schema.Enum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"array\"}\n\t\tschema.Items = &spec.SchemaOrArray{\n\t\t\tSchema: &spec.Schema{\n\t\t\t\tSchemaProps: spec.SchemaProps{\n\t\t\t\t\tType: []string{\"string\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,oneof=red green yellow\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []interface{}{\"red\", \"green\", \"yellow\"}, schema.Items.Schema.Enum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,oneof='red green' blue 'c0x2Cc' 'd0x7Cd'\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []interface{}{\"red green\", \"blue\", \"c,c\", \"d|d\"}, schema.Enum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,oneof='c0x9Ab' book\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []interface{}{\"c0x9Ab\", \"book\"}, schema.Enum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" binding:\"oneof=foo bar\" validate:\"required,oneof=foo bar\" enums:\"a,b,c\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []interface{}{\"a\", \"b\", \"c\"}, schema.Enum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"string\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" binding:\"oneof=aa bb\" validate:\"required,oneof=foo bar\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []interface{}{\"aa\", \"bb\"}, schema.Enum)\n\t})\n\tt.Run(\"Required with unique tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"array\"}\n\t\tschema.Items = &spec.SchemaOrArray{\n\t\t\tSchema: &spec.Schema{\n\t\t\t\tSchemaProps: spec.SchemaProps{\n\t\t\t\t\tType: []string{\"string\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,unique\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, true, schema.UniqueItems)\n\t})\n\n\tt.Run(\"All tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tschema := spec.Schema{}\n\t\tschema.Type = []string{\"array\"}\n\t\tschema.Items = &spec.SchemaOrArray{\n\t\t\tSchema: &spec.Schema{\n\t\t\t\tSchemaProps: spec.SchemaProps{\n\t\t\t\t\tType: []string{\"string\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\terr := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,unique,max=10,min=1,oneof=a0x2Cc 'c0x7Cd book',omitempty,dive,max=1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, true, schema.UniqueItems)\n\n\t\tmax := int64(10)\n\t\tmin := int64(1)\n\t\tassert.Equal(t, &max, schema.MaxItems)\n\t\tassert.Equal(t, &min, schema.MinItems)\n\t\tassert.Equal(t, []interface{}{\"a,c\", \"c|d book\"}, schema.Items.Schema.Enum)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"array\"}\n\t\tschema.Items = &spec.SchemaOrArray{\n\t\t\tSchema: &spec.Schema{\n\t\t\t\tSchemaProps: spec.SchemaProps{\n\t\t\t\t\tType: []string{\"string\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,oneof=,max=10=90,min=1\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Empty(t, schema.UniqueItems)\n\t\tassert.Empty(t, schema.MaxItems)\n\t\tassert.Equal(t, &min, schema.MinItems)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"array\"}\n\t\tschema.Items = &spec.SchemaOrArray{\n\t\t\tSchema: &spec.Schema{\n\t\t\t\tSchemaProps: spec.SchemaProps{\n\t\t\t\t\tType: []string{\"string\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{Tag: &ast.BasicLit{\n\t\t\t\tValue: `json:\"test\" validate:\"required,max=10,min=one\"`,\n\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, &max, schema.MaxItems)\n\t\tassert.Empty(t, schema.MinItems)\n\n\t\tschema = spec.Schema{}\n\t\tschema.Type = []string{\"integer\"}\n\t\terr = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{\n\t\t\t\tNames: []*ast.Ident{{Name: \"Test\"}},\n\t\t\t\tTag: &ast.BasicLit{\n\t\t\t\t\tValue: `json:\"test\" validate:\"required,oneof=one two\"`,\n\t\t\t\t}},\n\t\t).ComplementSchema(&schema)\n\t\tassert.NoError(t, err)\n\t\tassert.Empty(t, schema.Enum)\n\t})\n\n\tt.Run(\"Form Filed Name\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfilednames, err := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{\n\t\t\t\tNames: []*ast.Ident{{Name: \"Test\"}},\n\t\t\t\tTag: &ast.BasicLit{\n\t\t\t\t\tValue: `form:\"test[]\"`,\n\t\t\t\t}},\n\t\t).FieldNames()\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"test\", filednames[0])\n\n\t\tfilednames, err = newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{\n\t\t\t\tNames: []*ast.Ident{{Name: \"Test\"}},\n\t\t\t\tTag: &ast.BasicLit{\n\t\t\t\t\tValue: `form:\"test\"`,\n\t\t\t\t}},\n\t\t).FieldNames()\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"test\", filednames[0])\n\t})\n\n\tt.Run(\"Two Names\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfieldnames, err := newTagBaseFieldParser(\n\t\t\t&Parser{},\n\t\t\t&ast.Field{\n\t\t\t\tNames: []*ast.Ident{{Name: \"X\"}, {Name: \"Y\"}},\n\t\t\t},\n\t\t).FieldNames()\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, 2, len(fieldnames))\n\t\tassert.Equal(t, \"x\", fieldnames[0])\n\t\tassert.Equal(t, \"y\", fieldnames[1])\n\t})\n}\n"
  },
  {
    "path": "format/format.go",
    "content": "package format\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/swaggo/swag\"\n\t\"golang.org/x/sync/errgroup\"\n)\n\n// Format implements `fmt` command for formatting swag comments in Go source\n// files.\ntype Format struct {\n\tformatter *swag.Formatter\n\n\t// exclude exclude dirs and files in SearchDir\n\texclude map[string]bool\n}\n\n// New creates a new Format instance\nfunc New() *Format {\n\treturn &Format{\n\t\texclude:   map[string]bool{},\n\t\tformatter: swag.NewFormatter(),\n\t}\n}\n\n// Config specifies configuration for a format run\ntype Config struct {\n\t// SearchDir the swag would be parse\n\tSearchDir string\n\n\t// excludes dirs and files in SearchDir,comma separated\n\tExcludes string\n\n\t// MainFile (DEPRECATED)\n\tMainFile string\n}\n\nvar defaultExcludes = []string{\"docs\", \"vendor\"}\n\n// Build runs formatter according to configuration in config\nfunc (f *Format) Build(config *Config) error {\n\tsearchDirs := strings.Split(config.SearchDir, \",\")\n\tfor _, searchDir := range searchDirs {\n\t\tif _, err := os.Stat(searchDir); os.IsNotExist(err) {\n\t\t\treturn fmt.Errorf(\"fmt: %w\", err)\n\t\t}\n\t\tfor _, d := range defaultExcludes {\n\t\t\tf.exclude[filepath.Join(searchDir, d)] = true\n\t\t}\n\t}\n\tfor _, fi := range strings.Split(config.Excludes, \",\") {\n\t\tif fi = strings.TrimSpace(fi); fi != \"\" {\n\t\t\tf.exclude[filepath.Clean(fi)] = true\n\t\t}\n\t}\n\tvar eg errgroup.Group\n\teg.SetLimit(runtime.GOMAXPROCS(0))\n\tfor _, searchDir := range searchDirs {\n\t\terr := filepath.Walk(searchDir, func(path string, fileInfo fs.FileInfo, err error) error {\n\t\t\tif fileInfo.IsDir() && f.excludeDir(path) {\n\t\t\t\treturn filepath.SkipDir\n\t\t\t}\n\t\t\tif f.excludeFile(path) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\teg.Go(func() error {\n\t\t\t\treturn f.format(path)\n\t\t\t})\n\t\t\treturn nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := eg.Wait(); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (f *Format) excludeDir(path string) bool {\n\treturn f.exclude[path] ||\n\t\tfilepath.Base(path)[0] == '.' &&\n\t\t\tlen(filepath.Base(path)) > 1 // exclude hidden folders\n}\n\nfunc (f *Format) excludeFile(path string) bool {\n\treturn f.exclude[path] ||\n\t\tstrings.HasSuffix(strings.ToLower(path), \"_test.go\") ||\n\t\tfilepath.Ext(path) != \".go\"\n}\n\nfunc (f *Format) format(path string) error {\n\toriginal, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\tcontents := make([]byte, len(original))\n\tcopy(contents, original)\n\tformatted, err := f.formatter.Format(path, contents)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif bytes.Equal(original, formatted) {\n\t\t// Skip write if no change\n\t\treturn nil\n\t}\n\treturn write(path, formatted)\n}\n\nfunc write(path string, contents []byte) error {\n\toriginalFileInfo, err := os.Stat(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\tf, err := os.CreateTemp(filepath.Dir(path), filepath.Base(path))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer os.Remove(f.Name())\n\tif _, err := f.Write(contents); err != nil {\n\t\treturn err\n\t}\n\tif err := f.Close(); err != nil {\n\t\treturn err\n\t}\n\tif err := os.Chmod(f.Name(), originalFileInfo.Mode()); err != nil {\n\t\treturn err\n\t}\n\treturn os.Rename(f.Name(), path)\n}\n\n// Run the format on src and write the result to dst.\nfunc (f *Format) Run(src io.Reader, dst io.Writer) error {\n\tcontents, err := io.ReadAll(src)\n\tif err != nil {\n\t\treturn err\n\t}\n\tresult, err := f.formatter.Format(\"\", contents)\n\tif err != nil {\n\t\treturn err\n\t}\n\tr := bytes.NewReader(result)\n\tif _, err := io.Copy(dst, r); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "format/format_test.go",
    "content": "package format\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFormat_Format(t *testing.T) {\n\tfx := setup(t)\n\tassert.NoError(t, New().Build(&Config{SearchDir: fx.basedir}))\n\tassert.True(t, fx.isFormatted(\"main.go\"))\n\tassert.True(t, fx.isFormatted(\"api/api.go\"))\n}\n\nfunc TestFormat_PermissionsPreserved(t *testing.T) {\n\tfx := setup(t)\n\n\toriginalFileInfo, err := os.Stat(filepath.Join(fx.basedir, \"main.go\"))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tassert.NoError(t, New().Build(&Config{SearchDir: fx.basedir}))\n\tassert.True(t, permissionsEqual(t, filepath.Join(fx.basedir, \"main.go\"), originalFileInfo.Mode()))\n\tassert.True(t, permissionsEqual(t, filepath.Join(fx.basedir, \"api/api.go\"), originalFileInfo.Mode()))\n}\n\nfunc TestFormat_ExcludeDir(t *testing.T) {\n\tfx := setup(t)\n\tassert.NoError(t, New().Build(&Config{\n\t\tSearchDir: fx.basedir,\n\t\tExcludes:  filepath.Join(fx.basedir, \"api\"),\n\t}))\n\tassert.False(t, fx.isFormatted(\"api/api.go\"))\n}\n\nfunc TestFormat_ExcludeFile(t *testing.T) {\n\tfx := setup(t)\n\tassert.NoError(t, New().Build(&Config{\n\t\tSearchDir: fx.basedir,\n\t\tExcludes:  filepath.Join(fx.basedir, \"main.go\"),\n\t}))\n\tassert.False(t, fx.isFormatted(\"main.go\"))\n}\n\nfunc TestFormat_DefaultExcludes(t *testing.T) {\n\tfx := setup(t)\n\tassert.NoError(t, New().Build(&Config{SearchDir: fx.basedir}))\n\tassert.False(t, fx.isFormatted(\"api/api_test.go\"))\n\tassert.False(t, fx.isFormatted(\"docs/docs.go\"))\n}\n\nfunc TestFormat_ParseError(t *testing.T) {\n\tfx := setup(t)\n\tos.WriteFile(filepath.Join(fx.basedir, \"parse_error.go\"), []byte(`package main\n\t\tfunc invalid() {`), 0644)\n\tassert.Error(t, New().Build(&Config{SearchDir: fx.basedir}))\n}\n\nfunc TestFormat_ReadError(t *testing.T) {\n\tfx := setup(t)\n\tos.Chmod(filepath.Join(fx.basedir, \"main.go\"), 0)\n\tassert.Error(t, New().Build(&Config{SearchDir: fx.basedir}))\n}\n\nfunc TestFormat_WriteError(t *testing.T) {\n\tfx := setup(t)\n\tos.Chmod(fx.basedir, 0555)\n\tassert.Error(t, New().Build(&Config{SearchDir: fx.basedir}))\n\tos.Chmod(fx.basedir, 0755)\n}\n\nfunc TestFormat_InvalidSearchDir(t *testing.T) {\n\tformatter := New()\n\tassert.Error(t, formatter.Build(&Config{SearchDir: \"no_such_dir\"}))\n}\n\ntype fixture struct {\n\tt       *testing.T\n\tbasedir string\n}\n\nfunc setup(t *testing.T) *fixture {\n\tfx := &fixture{\n\t\tt:       t,\n\t\tbasedir: t.TempDir(),\n\t}\n\tfor filename, contents := range testFiles {\n\t\tfullpath := filepath.Join(fx.basedir, filepath.Clean(filename))\n\t\tif err := os.MkdirAll(filepath.Dir(fullpath), 0755); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tif err := os.WriteFile(fullpath, contents, 0644); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t}\n\treturn fx\n}\n\nfunc (fx *fixture) isFormatted(file string) bool {\n\tcontents, err := os.ReadFile(filepath.Join(fx.basedir, file))\n\tif err != nil {\n\t\tfx.t.Fatal(err)\n\t}\n\treturn !bytes.Equal(testFiles[file], contents)\n}\n\nfunc permissionsEqual(t *testing.T, path string, expectedMode os.FileMode) bool {\n\tfileInfo, err := os.Stat(path)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\treturn expectedMode == fileInfo.Mode()\n}\n\nvar testFiles = map[string][]byte{\n\t\"api/api.go\": []byte(`package api\n\n\t\timport \"net/http\"\n\n\t\t// @Summary\t\tAdd a new pet to the store\n\t\t// @Description\tget string by ID\n\t\tfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {\n\t\t\t//write your code\n\t\t}`),\n\t\"api/api_test.go\": []byte(`package api\n\t\t// @Summary API Test\n\t\t// @Description Should not be formatted\n\t\tfunc TestApi(t *testing.T) {}`),\n\t\"docs/docs.go\": []byte(`package docs\n\t\t// @Summary Documentation package\n\t\t// @Description Should not be formatted`),\n\t\"main.go\": []byte(`package main\n\n\t\timport (\n\t\t\t\"net/http\"\n\n\t\t\t\"github.com/swaggo/swag/format/testdata/api\"\n\t\t)\n\n\t\t// @title Swagger Example API\n\t\t// @version 1.0\n\t\tfunc main() {\n\t\t\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\t\t}`),\n\t\"README.md\": []byte(`# Format test`),\n}\n"
  },
  {
    "path": "formatter.go",
    "content": "package swag\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"go/ast\"\n\tgoparser \"go/parser\"\n\t\"go/token\"\n\t\"log\"\n\t\"os\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"golang.org/x/tools/imports\"\n)\n\n// Check of @Param @Success @Failure @Response @Header\nvar specialTagForSplit = map[string]bool{\n\tparamAttr:    true,\n\tsuccessAttr:  true,\n\tfailureAttr:  true,\n\tresponseAttr: true,\n\theaderAttr:   true,\n}\n\nvar skipChar = map[byte]byte{\n\t'\"': '\"',\n\t'(': ')',\n\t'{': '}',\n\t'[': ']',\n}\n\n// Formatter implements a formatter for Go source files.\ntype Formatter struct {\n\t// debugging output goes here\n\tdebug Debugger\n}\n\n// NewFormatter create a new formatter instance.\nfunc NewFormatter() *Formatter {\n\tformatter := &Formatter{\n\t\tdebug: log.New(os.Stdout, \"\", log.LstdFlags),\n\t}\n\treturn formatter\n}\n\n// Format formats swag comments in contents. It uses fileName to report errors\n// that happen during parsing of contents.\nfunc (f *Formatter) Format(fileName string, contents []byte) ([]byte, error) {\n\tfileSet := token.NewFileSet()\n\tastFile, err := goparser.ParseFile(fileSet, fileName, contents, goparser.ParseComments)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// We skip generated files to not interfere with the formatting and\n\t// introduce unnecessary changes.\n\tif ast.IsGenerated(astFile) {\n\t\treturn contents, nil\n\t}\n\n\t// Formatting changes are described as an edit list of byte range\n\t// replacements. We make these content-level edits directly rather than\n\t// changing the AST nodes and writing those out (via [go/printer] or\n\t// [go/format]) so that we only change the formatting of Swag attribute\n\t// comments. This won't touch the formatting of any other comments, or of\n\t// functions, etc.\n\tmaxEdits := 0\n\tfor _, comment := range astFile.Comments {\n\t\tmaxEdits += len(comment.List)\n\t}\n\tedits := make(edits, 0, maxEdits)\n\n\tfor _, comment := range astFile.Comments {\n\t\tformatFuncDoc(fileSet, comment.List, &edits)\n\t}\n\tformatted, err := imports.Process(fileName, edits.apply(contents), nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn formatted, nil\n}\n\ntype edit struct {\n\tbegin       int\n\tend         int\n\treplacement []byte\n}\n\ntype edits []edit\n\nfunc (edits edits) apply(contents []byte) []byte {\n\t// Apply the edits with the highest offset first, so that earlier edits\n\t// don't affect the offsets of later edits.\n\tsort.Slice(edits, func(i, j int) bool {\n\t\treturn edits[i].begin > edits[j].begin\n\t})\n\n\tfor _, edit := range edits {\n\t\tprefix := contents[:edit.begin]\n\t\tsuffix := contents[edit.end:]\n\t\tcontents = append(prefix, append(edit.replacement, suffix...)...)\n\t}\n\n\treturn contents\n}\n\n// formatFuncDoc reformats the comment lines in commentList, and appends any\n// changes to the edit list.\nfunc formatFuncDoc(fileSet *token.FileSet, commentList []*ast.Comment, edits *edits) {\n\t// Building the edit list to format a comment block is a two-step process.\n\t// First, we iterate over each comment line looking for Swag attributes. In\n\t// each one we find, we replace alignment whitespace with a tab character,\n\t// then write the result into a tab writer.\n\n\tlinesToComments := make(map[int]int, len(commentList))\n\n\tbuffer := &bytes.Buffer{}\n\tw := tabwriter.NewWriter(buffer, 1, 4, 1, '\\t', 0)\n\n\tfor commentIndex, comment := range commentList {\n\t\ttext := comment.Text\n\t\tif attr, body, found := swagComment(text); found {\n\t\t\tformatted := \"//\\t\" + attr\n\t\t\tif body != \"\" {\n\t\t\t\tformatted += \"\\t\" + splitComment2(attr, body)\n\t\t\t}\n\t\t\t_, _ = fmt.Fprintln(w, formatted)\n\t\t\tlinesToComments[len(linesToComments)] = commentIndex\n\t\t}\n\t}\n\n\t// Once we've loaded all of the comment lines to be aligned into the tab\n\t// writer, flushing it causes the aligned text to be written out to the\n\t// backing buffer.\n\t_ = w.Flush()\n\n\t// Now the second step: we iterate over the aligned comment lines that were\n\t// written into the backing buffer, pair each one up to its original\n\t// comment line, and use the combination to describe the edit that needs to\n\t// be made to the original input.\n\tformattedComments := bytes.Split(buffer.Bytes(), []byte(\"\\n\"))\n\tfor lineIndex, commentIndex := range linesToComments {\n\t\tcomment := commentList[commentIndex]\n\t\t*edits = append(*edits, edit{\n\t\t\tbegin:       fileSet.Position(comment.Pos()).Offset,\n\t\t\tend:         fileSet.Position(comment.End()).Offset,\n\t\t\treplacement: formattedComments[lineIndex],\n\t\t})\n\t}\n}\n\nfunc splitComment2(attr, body string) string {\n\tif specialTagForSplit[strings.ToLower(attr)] {\n\t\tfor i := 0; i < len(body); i++ {\n\t\t\tif skipEnd, ok := skipChar[body[i]]; ok {\n\t\t\t\tskipStart, n := body[i], 1\n\t\t\t\tfor i++; i < len(body); i++ {\n\t\t\t\t\tif skipStart != skipEnd && body[i] == skipStart {\n\t\t\t\t\t\tn++\n\t\t\t\t\t} else if body[i] == skipEnd {\n\t\t\t\t\t\tn--\n\t\t\t\t\t\tif n == 0 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if body[i] == ' ' || body[i] == '\\t' {\n\t\t\t\tj := i\n\t\t\t\tfor ; j < len(body) && (body[j] == ' ' || body[j] == '\\t'); j++ {\n\t\t\t\t}\n\t\t\t\tbody = replaceRange(body, i, j, \"\\t\")\n\t\t\t}\n\t\t}\n\t}\n\treturn body\n}\n\nfunc replaceRange(s string, start, end int, new string) string {\n\treturn s[:start] + new + s[end:]\n}\n\nvar swagCommentLineExpression = regexp.MustCompile(`^\\/\\/\\s+(@[\\S.]+)\\s*(.*)`)\n\nfunc swagComment(comment string) (string, string, bool) {\n\tmatches := swagCommentLineExpression.FindStringSubmatch(comment)\n\tif matches == nil {\n\t\treturn \"\", \"\", false\n\t}\n\treturn matches[1], matches[2], true\n}\n"
  },
  {
    "path": "formatter_test.go",
    "content": "package swag\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\tSearchDir = \"./testdata/format_test\"\n\tExcludes  = \"./testdata/format_test/web\"\n\tMainFile  = \"main.go\"\n)\n\nfunc testFormat(t *testing.T, filename, contents, want string) {\n\tgot, err := NewFormatter().Format(filename, []byte(contents))\n\tassert.NoError(t, err)\n\tassert.Equal(t, want, string(got))\n}\n\nfunc Test_FormatMain(t *testing.T) {\n\tcontents := `package main\n\t// @title Swagger Example API\n\t// @version 1.0\n\t// @description This is a sample server Petstore server.\n\t// @termsOfService http://swagger.io/terms/\n\n\t// @contact.name API Support\n\t// @contact.url http://www.swagger.io/support\n\t// @contact.email support@swagger.io\n\n\t// @license.name Apache 2.0\n\t// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n\t// @host petstore.swagger.io\n\t// @BasePath /v2\n\n\t// @securityDefinitions.basic BasicAuth\n\n\t// @securityDefinitions.apikey ApiKeyAuth\n\t// @in header\n\t// @name Authorization\n\n\t// @securitydefinitions.oauth2.application OAuth2Application\n\t// @tokenUrl https://example.com/oauth/token\n\t// @scope.write Grants write access\n\t// @scope.admin Grants read and write access to administrative information\n\n\t// @securitydefinitions.oauth2.implicit OAuth2Implicit\n\t// @authorizationurl https://example.com/oauth/authorize\n\t// @scope.write Grants write access\n\t// @scope.admin Grants read and write access to administrative information\n\n\t// @securitydefinitions.oauth2.password OAuth2Password\n\t// @tokenUrl https://example.com/oauth/token\n\t// @scope.read Grants read access\n\t// @scope.write Grants write access\n\t// @scope.admin Grants read and write access to administrative information\n\n\t// @securitydefinitions.oauth2.accessCode OAuth2AccessCode\n\t// @tokenUrl https://example.com/oauth/token\n\t// @authorizationurl https://example.com/oauth/authorize\n\t// @scope.admin Grants read and write access to administrative information\n\tfunc main() {}`\n\n\twant := `package main\n\n//\t@title\t\t\tSwagger Example API\n//\t@version\t\t1.0\n//\t@description\tThis is a sample server Petstore server.\n//\t@termsOfService\thttp://swagger.io/terms/\n\n//\t@contact.name\tAPI Support\n//\t@contact.url\thttp://www.swagger.io/support\n//\t@contact.email\tsupport@swagger.io\n\n//\t@license.name\tApache 2.0\n//\t@license.url\thttp://www.apache.org/licenses/LICENSE-2.0.html\n\n//\t@host\t\tpetstore.swagger.io\n//\t@BasePath\t/v2\n\n//\t@securityDefinitions.basic\tBasicAuth\n\n//\t@securityDefinitions.apikey\tApiKeyAuth\n//\t@in\t\t\t\t\t\t\theader\n//\t@name\t\t\t\t\t\tAuthorization\n\n//\t@securitydefinitions.oauth2.application\tOAuth2Application\n//\t@tokenUrl\t\t\t\t\t\t\t\thttps://example.com/oauth/token\n//\t@scope.write\t\t\t\t\t\t\tGrants write access\n//\t@scope.admin\t\t\t\t\t\t\tGrants read and write access to administrative information\n\n//\t@securitydefinitions.oauth2.implicit\tOAuth2Implicit\n//\t@authorizationurl\t\t\t\t\t\thttps://example.com/oauth/authorize\n//\t@scope.write\t\t\t\t\t\t\tGrants write access\n//\t@scope.admin\t\t\t\t\t\t\tGrants read and write access to administrative information\n\n//\t@securitydefinitions.oauth2.password\tOAuth2Password\n//\t@tokenUrl\t\t\t\t\t\t\t\thttps://example.com/oauth/token\n//\t@scope.read\t\t\t\t\t\t\t\tGrants read access\n//\t@scope.write\t\t\t\t\t\t\tGrants write access\n//\t@scope.admin\t\t\t\t\t\t\tGrants read and write access to administrative information\n\n// @securitydefinitions.oauth2.accessCode\tOAuth2AccessCode\n// @tokenUrl\t\t\t\t\t\t\t\thttps://example.com/oauth/token\n// @authorizationurl\t\t\t\t\t\thttps://example.com/oauth/authorize\n// @scope.admin\t\t\t\t\t\t\tGrants read and write access to administrative information\nfunc main() {}\n`\n\ttestFormat(t, \"main.go\", contents, want)\n}\n\nfunc Test_FormatMultipleFunctions(t *testing.T) {\n\tcontents := `package main\n\n// @Produce json\n// @Success 200 {object} string\n// @Failure 400 {object} string\n\tfunc A() {}\n\n// @Description Description of B.\n// @Produce json\n// @Success 200 {array} string\n// @Failure 400 {object} string\n\tfunc B() {}`\n\n\twant := `package main\n\n// @Produce\tjson\n// @Success\t200\t{object}\tstring\n// @Failure\t400\t{object}\tstring\nfunc A() {}\n\n// @Description\tDescription of B.\n// @Produce\t\tjson\n// @Success\t\t200\t{array}\t\tstring\n// @Failure\t\t400\t{object}\tstring\nfunc B() {}\n`\n\n\ttestFormat(t, \"main.go\", contents, want)\n}\n\nfunc Test_FormatApi(t *testing.T) {\n\tcontents := `package api\n\nimport \"net/http\"\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @ID get-string-by-int\n// @Accept  json\n// @Produce  json\n// @Param   some_id      path   int     true  \"Some ID\" Format(int64)\n// @Param   some_id      body web.Pet true  \"Some ID\"\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /testapi/get-string-by-int/{some_id} [get]\n\tfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {}`\n\n\twant := `package api\n\nimport \"net/http\"\n\n// @Summary\t\tAdd a new pet to the store\n// @Description\tget string by ID\n// @ID\t\t\t\tget-string-by-int\n// @Accept\t\t\tjson\n// @Produce\t\tjson\n// @Param\t\t\tsome_id\tpath\t\tint\t\t\t\ttrue\t\"Some ID\"\tFormat(int64)\n// @Param\t\t\tsome_id\tbody\t\tweb.Pet\t\t\ttrue\t\"Some ID\"\n// @Success\t\t200\t\t{string}\tstring\t\t\t\"ok\"\n// @Failure\t\t400\t\t{object}\tweb.APIError\t\"We need ID!!\"\n// @Failure\t\t404\t\t{object}\tweb.APIError\t\"Can not find ID\"\n// @Router\t\t\t/testapi/get-string-by-int/{some_id} [get]\nfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {}\n`\n\n\ttestFormat(t, \"api.go\", contents, want)\n}\n\nfunc Test_NonSwagComment(t *testing.T) {\n\tcontents := `package api\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @ID get-string-by-int\n// @ Accept json\n// This is not a @swag comment`\n\twant := `package api\n\n//\t@Summary\t\tAdd a new pet to the store\n//\t@Description\tget string by ID\n//\t@ID\t\t\t\tget-string-by-int\n// @ Accept json\n// This is not a @swag comment\n`\n\n\ttestFormat(t, \"non_swag.go\", contents, want)\n}\n\nfunc Test_EmptyComment(t *testing.T) {\n\tcontents := `package empty\n\n// @Summary Add a new pet to the store\n// @Description  `\n\twant := `package empty\n\n//\t@Summary\tAdd a new pet to the store\n//\t@Description\n`\n\n\ttestFormat(t, \"empty.go\", contents, want)\n}\n\nfunc Test_AlignAttribute(t *testing.T) {\n\tcontents := `package align\n\n// @Summary Add a new pet to the store\n//  @Description Description`\n\twant := `package align\n\n//\t@Summary\t\tAdd a new pet to the store\n//\t@Description\tDescription\n`\n\n\ttestFormat(t, \"align.go\", contents, want)\n\n}\n\nfunc Test_SyntaxError(t *testing.T) {\n\tcontents := []byte(`package invalid\n\tfunc invalid() {`)\n\n\t_, err := NewFormatter().Format(\"invalid.go\", contents)\n\tassert.Error(t, err)\n}\n\nfunc Test_splitComment2(t *testing.T) {\n\ttype args struct {\n\t\tattr string\n\t\tbody string\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant string\n\t}{\n\t\t{\n\t\t\t\"test_splitComment2_1\",\n\t\t\targs{\n\t\t\t\tattr: \"@param\",\n\t\t\t\tbody: \"   data body web.GenericBodyMulti[[]types.Post, [][]types.Post]\",\n\t\t\t},\n\t\t\t\"\\tdata\\tbody\\tweb.GenericBodyMulti[[]types.Post, [][]types.Post]\",\n\t\t},\n\t\t{\n\t\t\t\"test_splitComment2_2\",\n\t\t\targs{\n\t\t\t\tattr: \"@param\",\n\t\t\t\tbody: `   some_id      path   int     true  \"Some ID\" Format(int64)`,\n\t\t\t},\n\t\t\t\"\\tsome_id\\tpath\\tint\\ttrue\\t\\\"Some ID\\\"\\tFormat(int64)\",\n\t\t},\n\t\t{\n\t\t\t\"test_splitComment2_3\",\n\t\t\targs{\n\t\t\t\tattr: \"@param\",\n\t\t\t\tbody: `   @Param   some_id      body web.Pet true  \"Some ID\"`,\n\t\t\t},\n\t\t\t\"\\t@Param\\tsome_id\\tbody\\tweb.Pet\\ttrue\\t\\\"Some ID\\\"\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tassert.Equalf(t, tt.want, splitComment2(tt.args.attr, tt.args.body), \"splitComment2(%v, %v)\", tt.args.attr, tt.args.body)\n\t\t})\n\t}\n}\n\nfunc Test_FormatSkipGeneratedFile(t *testing.T) {\n\tcontents := `// Code generated by sqlc. DO NOT EDIT.\n// versions:\n//   sqlc v1.29.0\n\npackage storage\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n)\n\ntype DBTX interface {\n\tExecContext(context.Context, string, ...interface{}) (sql.Result, error)\n\tPrepareContext(context.Context, string) (*sql.Stmt, error)\n\tQueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)\n\tQueryRowContext(context.Context, string, ...interface{}) *sql.Row\n}\n\nfunc New(db DBTX) *Queries {\n\treturn &Queries{db: db}\n}\n\ntype Queries struct {\n\tdb DBTX\n}\n\nfunc (q *Queries) WithTx(tx *sql.Tx) *Queries {\n\treturn &Queries{\n\t\tdb: tx,\n\t}\n}\n`\n\n\twant := `// Code generated by sqlc. DO NOT EDIT.\n// versions:\n//   sqlc v1.29.0\n\npackage storage\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n)\n\ntype DBTX interface {\n\tExecContext(context.Context, string, ...interface{}) (sql.Result, error)\n\tPrepareContext(context.Context, string) (*sql.Stmt, error)\n\tQueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)\n\tQueryRowContext(context.Context, string, ...interface{}) *sql.Row\n}\n\nfunc New(db DBTX) *Queries {\n\treturn &Queries{db: db}\n}\n\ntype Queries struct {\n\tdb DBTX\n}\n\nfunc (q *Queries) WithTx(tx *sql.Tx) *Queries {\n\treturn &Queries{\n\t\tdb: tx,\n\t}\n}\n`\n\ttestFormat(t, \"db.sql.go\", contents, want)\n}\n"
  },
  {
    "path": "gen/gen.go",
    "content": "package gen\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"go/format\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"github.com/go-openapi/spec\"\n\t\"github.com/swaggo/swag\"\n\t\"golang.org/x/text/cases\"\n\t\"golang.org/x/text/language\"\n\t\"sigs.k8s.io/yaml\"\n)\n\nvar open = os.Open\n\n// DefaultOverridesFile is the location swagger will look for type overrides.\nconst DefaultOverridesFile = \".swaggo\"\n\ntype genTypeWriter func(*Config, *spec.Swagger) error\n\n// Gen presents a generate tool for swag.\ntype Gen struct {\n\tjson          func(data any) ([]byte, error)\n\tjsonIndent    func(data any) ([]byte, error)\n\tjsonToYAML    func(data []byte) ([]byte, error)\n\toutputTypeMap map[string]genTypeWriter\n\tdebug         Debugger\n}\n\n// Debugger is the interface that wraps the basic Printf method.\ntype Debugger interface {\n\tPrintf(format string, v ...any)\n}\n\n// New creates a new Gen.\nfunc New() *Gen {\n\tgen := Gen{\n\t\tjson: json.Marshal,\n\t\tjsonIndent: func(data any) ([]byte, error) {\n\t\t\treturn json.MarshalIndent(data, \"\", \"    \")\n\t\t},\n\t\tjsonToYAML: yaml.JSONToYAML,\n\t\tdebug:      log.New(os.Stdout, \"\", log.LstdFlags),\n\t}\n\n\tgen.outputTypeMap = map[string]genTypeWriter{\n\t\t\"go\":   gen.writeDocSwagger,\n\t\t\"json\": gen.writeJSONSwagger,\n\t\t\"yaml\": gen.writeYAMLSwagger,\n\t\t\"yml\":  gen.writeYAMLSwagger,\n\t}\n\n\treturn &gen\n}\n\n// Config presents Gen configurations.\ntype Config struct {\n\tDebugger swag.Debugger\n\n\t// SearchDir the swag would parse,comma separated if multiple\n\tSearchDir string\n\n\t// excludes dirs and files in SearchDir,comma separated\n\tExcludes string\n\n\t// outputs only specific extension\n\tParseExtension string\n\n\t// OutputDir represents the output directory for all the generated files\n\tOutputDir string\n\n\t// OutputTypes define types of files which should be generated\n\tOutputTypes []string\n\n\t// MainAPIFile the Go file path in which 'swagger general API Info' is written\n\tMainAPIFile string\n\n\t// PropNamingStrategy represents property naming strategy like snake case,camel case,pascal case\n\tPropNamingStrategy string\n\n\t// MarkdownFilesDir used to find markdown files, which can be used for tag descriptions\n\tMarkdownFilesDir string\n\n\t// CodeExampleFilesDir used to find code example files, which can be used for x-codeSamples\n\tCodeExampleFilesDir string\n\n\t// InstanceName is used to get distinct names for different swagger documents in the\n\t// same project. The default value is \"swagger\".\n\tInstanceName string\n\n\t// ParseDepth dependency parse depth\n\tParseDepth int\n\n\t// ParseVendor whether swag should be parse vendor folder\n\tParseVendor bool\n\n\t// ParseDependencies whether swag should be parse outside dependency folder: 0 none, 1 models, 2 operations, 3 all\n\tParseDependency int\n\n\t// UseStructNames stick to the struct name instead of those ugly full-path names\n\tUseStructNames bool\n\n\t// ParseInternal whether swag should parse internal packages\n\tParseInternal bool\n\n\t// Strict whether swag should error or warn when it detects cases which are most likely user errors\n\tStrict bool\n\n\t// GeneratedTime whether swag should generate the timestamp at the top of docs.go\n\tGeneratedTime bool\n\n\t// RequiredByDefault set validation required for all fields by default\n\tRequiredByDefault bool\n\n\t// OverridesFile defines global type overrides.\n\tOverridesFile string\n\n\t// ParseGoList whether swag use go list to parse dependency\n\tParseGoList bool\n\n\t// include only tags mentioned when searching, comma separated\n\tTags string\n\n\t// LeftTemplateDelim defines the left delimiter for the template generation\n\tLeftTemplateDelim string\n\n\t// RightTemplateDelim defines the right delimiter for the template generation\n\tRightTemplateDelim string\n\n\t// PackageName defines package name of generated `docs.go`\n\tPackageName string\n\n\t// CollectionFormat set default collection format\n\tCollectionFormat string\n\n\t// Parse only packages whose import path match the given prefix, comma separated\n\tPackagePrefix string\n\n\t// State set host state\n\tState string\n\n\t// ParseFuncBody whether swag should parse api info inside of funcs\n\tParseFuncBody bool\n\n\t// ParseGoPackages whether swag use golang.org/x/tools/go/packages to parse source.\n\tParseGoPackages bool\n}\n\n// Build builds swagger json file  for given searchDir and mainAPIFile. Returns json.\nfunc (g *Gen) Build(config *Config) error {\n\tif config.Debugger != nil {\n\t\tg.debug = config.Debugger\n\t}\n\tif config.InstanceName == \"\" {\n\t\tconfig.InstanceName = swag.Name\n\t}\n\n\tsearchDirs := strings.Split(config.SearchDir, \",\")\n\tif !config.ParseGoPackages { // packages.Load support pattern like ./...\n\t\tfor _, searchDir := range searchDirs {\n\t\t\tif _, err := os.Stat(searchDir); os.IsNotExist(err) {\n\t\t\t\treturn fmt.Errorf(\"dir: %s does not exist\", searchDir)\n\t\t\t}\n\t\t}\n\t}\n\n\tif config.LeftTemplateDelim == \"\" {\n\t\tconfig.LeftTemplateDelim = \"{{\"\n\t}\n\n\tif config.RightTemplateDelim == \"\" {\n\t\tconfig.RightTemplateDelim = \"}}\"\n\t}\n\n\tvar overrides map[string]string\n\n\tif config.OverridesFile != \"\" {\n\t\toverridesFile, err := open(config.OverridesFile)\n\t\tif err != nil {\n\t\t\t// Don't bother reporting if the default file is missing; assume there are no overrides\n\t\t\tif !(config.OverridesFile == DefaultOverridesFile && os.IsNotExist(err)) {\n\t\t\t\treturn fmt.Errorf(\"could not open overrides file: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tg.debug.Printf(\"Using overrides from %s\", config.OverridesFile)\n\n\t\t\toverrides, err = parseOverrides(overridesFile)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tg.debug.Printf(\"Generate swagger docs....\")\n\n\tp := swag.New(\n\t\tswag.SetParseDependency(config.ParseDependency),\n\t\tswag.SetUseStructName(config.UseStructNames),\n\t\tswag.SetMarkdownFileDirectory(config.MarkdownFilesDir),\n\t\tswag.SetDebugger(config.Debugger),\n\t\tswag.SetExcludedDirsAndFiles(config.Excludes),\n\t\tswag.SetParseExtension(config.ParseExtension),\n\t\tswag.SetCodeExamplesDirectory(config.CodeExampleFilesDir),\n\t\tswag.SetStrict(config.Strict),\n\t\tswag.SetOverrides(overrides),\n\t\tswag.ParseUsingGoList(config.ParseGoList),\n\t\tswag.SetTags(config.Tags),\n\t\tswag.SetCollectionFormat(config.CollectionFormat),\n\t\tswag.SetPackagePrefix(config.PackagePrefix),\n\t)\n\n\tp.PropNamingStrategy = config.PropNamingStrategy\n\tp.ParseVendor = config.ParseVendor\n\tp.ParseInternal = config.ParseInternal\n\tp.RequiredByDefault = config.RequiredByDefault\n\tp.HostState = config.State\n\tp.ParseFuncBody = config.ParseFuncBody\n\tp.ParseGoPackages = config.ParseGoPackages\n\n\tif err := p.ParseAPIMultiSearchDir(searchDirs, config.MainAPIFile, config.ParseDepth); err != nil {\n\t\treturn err\n\t}\n\n\tswagger := p.GetSwagger()\n\n\tif err := os.MkdirAll(config.OutputDir, os.ModePerm); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, outputType := range config.OutputTypes {\n\t\toutputType = strings.ToLower(strings.TrimSpace(outputType))\n\t\tif typeWriter, ok := g.outputTypeMap[outputType]; ok {\n\t\t\tif err := typeWriter(config, swagger); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tlog.Printf(\"output type '%s' not supported\", outputType)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (g *Gen) writeDocSwagger(config *Config, swagger *spec.Swagger) error {\n\tvar filename = \"docs.go\"\n\n\tif config.State != \"\" {\n\t\tfilename = config.State + \"_\" + filename\n\t}\n\n\tif config.InstanceName != swag.Name {\n\t\tfilename = config.InstanceName + \"_\" + filename\n\t}\n\n\tdocFileName := path.Join(config.OutputDir, filename)\n\n\tabsOutputDir, err := filepath.Abs(config.OutputDir)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar packageName string\n\tif len(config.PackageName) > 0 {\n\t\tpackageName = config.PackageName\n\t} else {\n\t\tpackageName = filepath.Base(absOutputDir)\n\t\tpackageName = strings.ReplaceAll(packageName, \"-\", \"_\")\n\t}\n\n\tdocs, err := os.Create(docFileName)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer docs.Close()\n\n\t// Write doc\n\terr = g.writeGoDoc(packageName, docs, swagger, config)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tg.debug.Printf(\"create docs.go at %+v\", docFileName)\n\n\treturn nil\n}\n\nfunc (g *Gen) writeJSONSwagger(config *Config, swagger *spec.Swagger) error {\n\tvar filename = \"swagger.json\"\n\n\tif config.State != \"\" {\n\t\tfilename = config.State + \"_\" + filename\n\t}\n\n\tif config.InstanceName != swag.Name {\n\t\tfilename = config.InstanceName + \"_\" + filename\n\t}\n\n\tjsonFileName := path.Join(config.OutputDir, filename)\n\n\tb, err := g.jsonIndent(swagger)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = g.writeFile(b, jsonFileName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tg.debug.Printf(\"create swagger.json at %+v\", jsonFileName)\n\n\treturn nil\n}\n\nfunc (g *Gen) writeYAMLSwagger(config *Config, swagger *spec.Swagger) error {\n\tvar filename = \"swagger.yaml\"\n\n\tif config.State != \"\" {\n\t\tfilename = config.State + \"_\" + filename\n\t}\n\n\tif config.InstanceName != swag.Name {\n\t\tfilename = config.InstanceName + \"_\" + filename\n\t}\n\n\tyamlFileName := path.Join(config.OutputDir, filename)\n\n\tb, err := g.json(swagger)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ty, err := g.jsonToYAML(b)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot covert json to yaml error: %s\", err)\n\t}\n\n\terr = g.writeFile(y, yamlFileName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tg.debug.Printf(\"create swagger.yaml at %+v\", yamlFileName)\n\n\treturn nil\n}\n\nfunc (g *Gen) writeFile(b []byte, file string) error {\n\tf, err := os.Create(file)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer f.Close()\n\n\t_, err = f.Write(b)\n\n\treturn err\n}\n\nfunc (g *Gen) formatSource(src []byte) []byte {\n\tcode, err := format.Source(src)\n\tif err != nil {\n\t\tcode = src // Formatter failed, return original code.\n\t}\n\n\treturn code\n}\n\n// Read and parse the overrides file.\nfunc parseOverrides(r io.Reader) (map[string]string, error) {\n\toverrides := make(map[string]string)\n\tscanner := bufio.NewScanner(r)\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\t// Skip comments\n\t\tif len(line) > 1 && line[0:2] == \"//\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tparts := strings.Fields(line)\n\n\t\tswitch len(parts) {\n\t\tcase 0:\n\t\t\t// only whitespace\n\t\t\tcontinue\n\t\tcase 2:\n\t\t\t// either a skip or malformed\n\t\t\tif parts[0] != \"skip\" {\n\t\t\t\treturn nil, fmt.Errorf(\"could not parse override: '%s'\", line)\n\t\t\t}\n\n\t\t\toverrides[parts[1]] = \"\"\n\t\tcase 3:\n\t\t\t// either a replace or malformed\n\t\t\tif parts[0] != \"replace\" {\n\t\t\t\treturn nil, fmt.Errorf(\"could not parse override: '%s'\", line)\n\t\t\t}\n\n\t\t\toverrides[parts[1]] = parts[2]\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"could not parse override: '%s'\", line)\n\t\t}\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"error reading overrides file: %w\", err)\n\t}\n\n\treturn overrides, nil\n}\n\nfunc (g *Gen) writeGoDoc(packageName string, output io.Writer, swagger *spec.Swagger, config *Config) error {\n\tgenerator, err := template.New(\"swagger_info\").Funcs(template.FuncMap{\n\t\t\"printDoc\": func(v string) string {\n\t\t\t// Add schemes\n\t\t\tv = \"{\\n    \\\"schemes\\\": \" + config.LeftTemplateDelim + \" marshal .Schemes \" + config.RightTemplateDelim + \",\" + v[1:]\n\t\t\t// Sanitize backticks\n\t\t\treturn strings.Replace(v, \"`\", \"`+\\\"`\\\"+`\", -1)\n\t\t},\n\t}).Parse(packageTemplate)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tswaggerSpec := &spec.Swagger{\n\t\tVendorExtensible: swagger.VendorExtensible,\n\t\tSwaggerProps: spec.SwaggerProps{\n\t\t\tID:       swagger.ID,\n\t\t\tConsumes: swagger.Consumes,\n\t\t\tProduces: swagger.Produces,\n\t\t\tSwagger:  swagger.Swagger,\n\t\t\tInfo: &spec.Info{\n\t\t\t\tVendorExtensible: swagger.Info.VendorExtensible,\n\t\t\t\tInfoProps: spec.InfoProps{\n\t\t\t\t\tDescription:    config.LeftTemplateDelim + \"escape .Description\" + config.RightTemplateDelim,\n\t\t\t\t\tTitle:          config.LeftTemplateDelim + \".Title\" + config.RightTemplateDelim,\n\t\t\t\t\tTermsOfService: swagger.Info.TermsOfService,\n\t\t\t\t\tContact:        swagger.Info.Contact,\n\t\t\t\t\tLicense:        swagger.Info.License,\n\t\t\t\t\tVersion:        config.LeftTemplateDelim + \".Version\" + config.RightTemplateDelim,\n\t\t\t\t},\n\t\t\t},\n\t\t\tHost:                config.LeftTemplateDelim + \".Host\" + config.RightTemplateDelim,\n\t\t\tBasePath:            config.LeftTemplateDelim + \".BasePath\" + config.RightTemplateDelim,\n\t\t\tPaths:               swagger.Paths,\n\t\t\tDefinitions:         swagger.Definitions,\n\t\t\tParameters:          swagger.Parameters,\n\t\t\tResponses:           swagger.Responses,\n\t\t\tSecurityDefinitions: swagger.SecurityDefinitions,\n\t\t\tSecurity:            swagger.Security,\n\t\t\tTags:                swagger.Tags,\n\t\t\tExternalDocs:        swagger.ExternalDocs,\n\t\t},\n\t}\n\n\t// crafted docs.json\n\tbuf, err := g.jsonIndent(swaggerSpec)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstate := \"\"\n\tif len(config.State) > 0 {\n\t\tstate = cases.Title(language.English).String(strings.ToLower(config.State))\n\t}\n\n\tbuffer := &bytes.Buffer{}\n\n\terr = generator.Execute(buffer, struct {\n\t\tTimestamp          time.Time\n\t\tDoc                string\n\t\tHost               string\n\t\tPackageName        string\n\t\tBasePath           string\n\t\tTitle              string\n\t\tDescription        string\n\t\tVersion            string\n\t\tState              string\n\t\tInstanceName       string\n\t\tSchemes            []string\n\t\tGeneratedTime      bool\n\t\tLeftTemplateDelim  string\n\t\tRightTemplateDelim string\n\t}{\n\t\tTimestamp:          time.Now(),\n\t\tGeneratedTime:      config.GeneratedTime,\n\t\tDoc:                string(buf),\n\t\tHost:               swagger.Host,\n\t\tPackageName:        packageName,\n\t\tBasePath:           swagger.BasePath,\n\t\tSchemes:            swagger.Schemes,\n\t\tTitle:              swagger.Info.Title,\n\t\tDescription:        swagger.Info.Description,\n\t\tVersion:            swagger.Info.Version,\n\t\tState:              state,\n\t\tInstanceName:       config.InstanceName,\n\t\tLeftTemplateDelim:  config.LeftTemplateDelim,\n\t\tRightTemplateDelim: config.RightTemplateDelim,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcode := g.formatSource(buffer.Bytes())\n\n\t// write\n\t_, err = output.Write(code)\n\n\treturn err\n}\n\nvar packageTemplate = `// Package {{.PackageName}} Code generated by swaggo/swag{{ if .GeneratedTime }} at {{ .Timestamp }}{{ end }}. DO NOT EDIT\npackage {{.PackageName}}\n\nimport \"github.com/swaggo/swag\"\n\nconst docTemplate{{ if ne .InstanceName \"swagger\" }}{{ .InstanceName }} {{- end }}{{ .State }} = ` + \"`{{ printDoc .Doc}}`\" + `\n\n// Swagger{{ .State }}Info{{ if ne .InstanceName \"swagger\" }}{{ .InstanceName }} {{- end }} holds exported Swagger Info so clients can modify it\nvar Swagger{{ .State }}Info{{ if ne .InstanceName \"swagger\" }}{{ .InstanceName }} {{- end }} = &swag.Spec{\n\tVersion:     {{ printf \"%q\" .Version}},\n\tHost:        {{ printf \"%q\" .Host}},\n\tBasePath:    {{ printf \"%q\" .BasePath}},\n\tSchemes:     []string{ {{ range $index, $schema := .Schemes}}{{if gt $index 0}},{{end}}{{printf \"%q\" $schema}}{{end}} },\n\tTitle:       {{ printf \"%q\" .Title}},\n\tDescription: {{ printf \"%q\" .Description}},\n\tInfoInstanceName: {{ printf \"%q\" .InstanceName }},\n\tSwaggerTemplate: docTemplate{{ if ne .InstanceName \"swagger\" }}{{ .InstanceName }} {{- end }}{{ .State }},\n\tLeftDelim:        {{ printf \"%q\" .LeftTemplateDelim}},\n\tRightDelim:       {{ printf \"%q\" .RightTemplateDelim}},\n}\n\nfunc init() {\n\tswag.Register(Swagger{{ .State }}Info{{ if ne .InstanceName \"swagger\" }}{{ .InstanceName }} {{- end }}.InstanceName(), Swagger{{ .State }}Info{{ if ne .InstanceName \"swagger\" }}{{ .InstanceName }} {{- end }})\n}\n`\n"
  },
  {
    "path": "gen/gen_test.go",
    "content": "package gen\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"plugin\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/go-openapi/spec\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/swaggo/swag\"\n)\n\nconst searchDir = \"../testdata/simple\"\n\nvar outputTypes = []string{\"go\", \"json\", \"yaml\"}\n\nfunc TestGen_Build(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t}\n\tassert.NoError(t, New().Build(config))\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.yaml\"),\n\t}\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\n\t\t_ = os.Remove(expectedFile)\n\t}\n}\n\nfunc TestGen_SpecificOutputTypes(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple/docs\",\n\t\tOutputTypes:        []string{\"go\", \"unknownType\"},\n\t\tPropNamingStrategy: \"\",\n\t}\n\tassert.NoError(t, New().Build(config))\n\n\ttt := []struct {\n\t\texpectedFile string\n\t\tshouldExist  bool\n\t}{\n\t\t{filepath.Join(config.OutputDir, \"docs.go\"), true},\n\t\t{filepath.Join(config.OutputDir, \"swagger.json\"), false},\n\t\t{filepath.Join(config.OutputDir, \"swagger.yaml\"), false},\n\t}\n\tfor _, tc := range tt {\n\t\t_, err := os.Stat(tc.expectedFile)\n\t\tif tc.shouldExist {\n\t\t\tif os.IsNotExist(err) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t} else {\n\t\t\trequire.Error(t, err)\n\t\t\trequire.True(t, errors.Is(err, os.ErrNotExist))\n\t\t}\n\n\t\t_ = os.Remove(tc.expectedFile)\n\t}\n}\n\nfunc TestGen_BuildInstanceName(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t}\n\tassert.NoError(t, New().Build(config))\n\n\tgoSourceFile := filepath.Join(config.OutputDir, \"docs.go\")\n\n\t// Validate default registration name\n\texpectedCode, err := os.ReadFile(goSourceFile)\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\tif !strings.Contains(\n\t\tstring(expectedCode),\n\t\t\"swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)\",\n\t) {\n\t\tt.Fatal(errors.New(\"generated go code does not contain the correct default registration sequence\"))\n\t}\n\n\tif !strings.Contains(\n\t\tstring(expectedCode),\n\t\t\"var SwaggerInfo =\",\n\t) {\n\t\tt.Fatal(errors.New(\"generated go code does not contain the correct default variable declaration\"))\n\t}\n\n\t// Custom name\n\tconfig.InstanceName = \"Custom\"\n\tgoSourceFile = filepath.Join(config.OutputDir, config.InstanceName+\"_\"+\"docs.go\")\n\tassert.NoError(t, New().Build(config))\n\n\texpectedCode, err = os.ReadFile(goSourceFile)\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\tif !strings.Contains(\n\t\tstring(expectedCode),\n\t\t\"swag.Register(SwaggerInfoCustom.InstanceName(), SwaggerInfoCustom)\",\n\t) {\n\t\tt.Fatal(errors.New(\"generated go code does not contain the correct registration sequence\"))\n\t}\n\n\tif !strings.Contains(\n\t\tstring(expectedCode),\n\t\t\"var SwaggerInfoCustom =\",\n\t) {\n\t\tt.Fatal(errors.New(\"generated go code does not contain the correct variable declaration\"))\n\t}\n\n\t// cleanup\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, config.InstanceName+\"_\"+\"docs.go\"),\n\t\tfilepath.Join(config.OutputDir, config.InstanceName+\"_\"+\"swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, config.InstanceName+\"_\"+\"swagger.yaml\"),\n\t}\n\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\n\t\t_ = os.Remove(expectedFile)\n\t}\n}\n\nfunc TestGen_BuildSnakeCase(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          \"../testdata/simple2\",\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple2/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: swag.SnakeCase,\n\t}\n\n\tassert.NoError(t, New().Build(config))\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.yaml\"),\n\t}\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\n\t\t_ = os.Remove(expectedFile)\n\t}\n}\n\nfunc TestGen_BuildLowerCamelcase(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          \"../testdata/simple3\",\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple3/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t}\n\n\tassert.NoError(t, New().Build(config))\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.yaml\"),\n\t}\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\n\t\t_ = os.Remove(expectedFile)\n\t}\n}\n\nfunc TestGen_BuildDescriptionWithQuotes(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:        \"../testdata/quotes\",\n\t\tMainAPIFile:      \"./main.go\",\n\t\tOutputDir:        \"../testdata/quotes/docs\",\n\t\tOutputTypes:      outputTypes,\n\t\tMarkdownFilesDir: \"../testdata/quotes\",\n\t}\n\n\trequire.NoError(t, New().Build(config))\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.yaml\"),\n\t}\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t}\n\n\tcmd := exec.Command(\"go\", \"build\", \"-buildmode=plugin\", \"github.com/swaggo/swag/testdata/quotes\")\n\n\tcmd.Dir = config.SearchDir\n\n\toutput, err := cmd.CombinedOutput()\n\tif err != nil {\n\t\trequire.NoError(t, err, string(output))\n\t}\n\n\tp, err := plugin.Open(filepath.Join(config.SearchDir, \"quotes.so\"))\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\tdefer os.Remove(\"quotes.so\")\n\n\treadDoc, err := p.Lookup(\"ReadDoc\")\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\tjsonOutput := readDoc.(func() string)()\n\n\tvar jsonDoc interface{}\n\tif err := json.Unmarshal([]byte(jsonOutput), &jsonDoc); err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\texpectedJSON, err := os.ReadFile(filepath.Join(config.SearchDir, \"expected.json\"))\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\tassert.JSONEq(t, string(expectedJSON), jsonOutput)\n}\n\nfunc TestGen_BuildDocCustomDelims(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          \"../testdata/delims\",\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/delims/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tMarkdownFilesDir:   \"../testdata/delims\",\n\t\tInstanceName:       \"CustomDelims\",\n\t\tLeftTemplateDelim:  \"{%\",\n\t\tRightTemplateDelim: \"%}\",\n\t}\n\n\trequire.NoError(t, New().Build(config))\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"CustomDelims_docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"CustomDelims_swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"CustomDelims_swagger.yaml\"),\n\t}\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t}\n\n\tcmd := exec.Command(\"go\", \"build\", \"-buildmode=plugin\", \"github.com/swaggo/swag/testdata/delims\")\n\n\tcmd.Dir = config.SearchDir\n\n\toutput, err := cmd.CombinedOutput()\n\tif err != nil {\n\t\trequire.NoError(t, err, string(output))\n\t}\n\n\tp, err := plugin.Open(filepath.Join(config.SearchDir, \"delims.so\"))\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\tdefer os.Remove(\"delims.so\")\n\n\treadDoc, err := p.Lookup(\"ReadDoc\")\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\tjsonOutput := readDoc.(func() string)()\n\n\tvar jsonDoc interface{}\n\tif err := json.Unmarshal([]byte(jsonOutput), &jsonDoc); err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\texpectedJSON, err := os.ReadFile(filepath.Join(config.SearchDir, \"expected.json\"))\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\tassert.JSONEq(t, string(expectedJSON), jsonOutput)\n}\n\nfunc TestGen_jsonIndent(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t}\n\n\tgen := New()\n\tgen.jsonIndent = func(data interface{}) ([]byte, error) {\n\t\treturn nil, errors.New(\"fail\")\n\t}\n\n\tassert.Error(t, gen.Build(config))\n}\n\nfunc TestGen_jsonToYAML(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t}\n\n\tgen := New()\n\tgen.jsonToYAML = func(data []byte) ([]byte, error) {\n\t\treturn nil, errors.New(\"fail\")\n\t}\n\tassert.Error(t, gen.Build(config))\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.json\"),\n\t}\n\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\n\t\t_ = os.Remove(expectedFile)\n\t}\n}\n\nfunc TestGen_SearchDirIsNotExist(t *testing.T) {\n\tvar swaggerConfDir, propNamingStrategy string\n\n\tconfig := &Config{\n\t\tSearchDir:          \"../isNotExistDir\",\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          swaggerConfDir,\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: propNamingStrategy,\n\t}\n\n\tassert.EqualError(t, New().Build(config), \"dir: ../isNotExistDir does not exist\")\n}\n\nfunc TestGen_MainAPiNotExist(t *testing.T) {\n\tvar swaggerConfDir, propNamingStrategy string\n\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./notExists.go\",\n\t\tOutputDir:          swaggerConfDir,\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: propNamingStrategy,\n\t}\n\n\tassert.Error(t, New().Build(config))\n}\n\nfunc TestGen_OutputIsNotExist(t *testing.T) {\n\tvar propNamingStrategy string\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"/dev/null\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: propNamingStrategy,\n\t}\n\tassert.Error(t, New().Build(config))\n}\n\nfunc TestGen_FailToWrite(t *testing.T) {\n\toutputDir := filepath.Join(os.TempDir(), \"swagg\", \"test\")\n\toutputTypes := []string{\"go\", \"json\", \"yaml\"}\n\n\tvar propNamingStrategy string\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          outputDir,\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: propNamingStrategy,\n\t}\n\n\terr := os.MkdirAll(outputDir, 0755)\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\t_ = os.RemoveAll(filepath.Join(outputDir, \"swagger.yaml\"))\n\n\terr = os.Mkdir(filepath.Join(outputDir, \"swagger.yaml\"), 0755)\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\tassert.Error(t, New().Build(config))\n\n\t_ = os.RemoveAll(filepath.Join(outputDir, \"swagger.json\"))\n\n\terr = os.Mkdir(filepath.Join(outputDir, \"swagger.json\"), 0755)\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\tassert.Error(t, New().Build(config))\n\n\t_ = os.RemoveAll(filepath.Join(outputDir, \"docs.go\"))\n\n\terr = os.Mkdir(filepath.Join(outputDir, \"docs.go\"), 0755)\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\tassert.Error(t, New().Build(config))\n\n\terr = os.RemoveAll(outputDir)\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n}\n\nfunc TestGen_configWithOutputDir(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t}\n\n\tassert.NoError(t, New().Build(config))\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.yaml\"),\n\t}\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\n\t\t_ = os.Remove(expectedFile)\n\t}\n}\n\nfunc TestGen_configWithOutputTypesAll(t *testing.T) {\n\tsearchDir := \"../testdata/simple\"\n\toutputTypes := []string{\"go\", \"json\", \"yaml\"}\n\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t}\n\n\tassert.NoError(t, New().Build(config))\n\n\texpectedFiles := []string{\n\t\tpath.Join(config.OutputDir, \"docs.go\"),\n\t\tpath.Join(config.OutputDir, \"swagger.json\"),\n\t\tpath.Join(config.OutputDir, \"swagger.yaml\"),\n\t}\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\t_ = os.Remove(expectedFile)\n\t}\n}\n\nfunc TestGen_configWithOutputTypesSingle(t *testing.T) {\n\tsearchDir := \"../testdata/simple\"\n\toutputTypes := []string{\"go\", \"json\", \"yaml\"}\n\n\tfor _, outputType := range outputTypes {\n\t\tconfig := &Config{\n\t\t\tSearchDir:          searchDir,\n\t\t\tMainAPIFile:        \"./main.go\",\n\t\t\tOutputDir:          \"../testdata/simple/docs\",\n\t\t\tOutputTypes:        []string{outputType},\n\t\t\tPropNamingStrategy: \"\",\n\t\t}\n\n\t\tassert.NoError(t, New().Build(config))\n\n\t\toutFileName := \"swagger\"\n\t\tif outputType == \"go\" {\n\t\t\toutFileName = \"docs\"\n\t\t}\n\n\t\texpectedFiles := []string{\n\t\t\tpath.Join(config.OutputDir, outFileName+\".\"+outputType),\n\t\t}\n\t\tfor _, expectedFile := range expectedFiles {\n\t\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\t\t_ = os.Remove(expectedFile)\n\t\t}\n\t}\n}\n\nfunc TestGen_formatSource(t *testing.T) {\n\tsrc := `package main\n\nimport \"net\n\nfunc main() {}\n`\n\tg := New()\n\n\tres := g.formatSource([]byte(src))\n\tassert.Equal(t, []byte(src), res, \"Should return same content due to fmt fail\")\n\n\tsrc2 := `package main\n\nimport \"fmt\"\n\nfunc main() {\nfmt.Print(\"Hello world\")\n}\n`\n\tres = g.formatSource([]byte(src2))\n\tassert.NotEqual(t, []byte(src2), res, \"Should return fmt code\")\n}\n\ntype mockWriter struct {\n\thook func([]byte)\n}\n\nfunc (w *mockWriter) Write(data []byte) (int, error) {\n\tif w.hook != nil {\n\t\tw.hook(data)\n\t}\n\n\treturn len(data), nil\n}\n\nfunc TestGen_writeGoDoc(t *testing.T) {\n\tgen := New()\n\n\tswapTemplate := packageTemplate\n\n\tpackageTemplate = `{{{`\n\terr := gen.writeGoDoc(\"docs\", nil, nil, &Config{})\n\tassert.Error(t, err)\n\n\tpackageTemplate = `{{.Data}}`\n\tswagger := &spec.Swagger{\n\t\tVendorExtensible: spec.VendorExtensible{},\n\t\tSwaggerProps: spec.SwaggerProps{\n\t\t\tInfo: &spec.Info{},\n\t\t},\n\t}\n\n\terr = gen.writeGoDoc(\"docs\", &mockWriter{}, swagger, &Config{})\n\tassert.Error(t, err)\n\n\tpackageTemplate = `{{ if .GeneratedTime }}Fake Time{{ end }}`\n\terr = gen.writeGoDoc(\"docs\",\n\t\t&mockWriter{\n\t\t\thook: func(data []byte) {\n\t\t\t\tassert.Equal(t, \"Fake Time\", string(data))\n\t\t\t},\n\t\t}, swagger, &Config{GeneratedTime: true})\n\tassert.NoError(t, err)\n\n\terr = gen.writeGoDoc(\"docs\",\n\t\t&mockWriter{\n\t\t\thook: func(data []byte) {\n\t\t\t\tassert.Equal(t, \"\", string(data))\n\t\t\t},\n\t\t}, swagger, &Config{GeneratedTime: false})\n\tassert.NoError(t, err)\n\n\tpackageTemplate = swapTemplate\n}\n\nfunc TestGen_GeneratedDoc(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t}\n\n\tassert.NoError(t, New().Build(config))\n\n\tgoCMD, err := exec.LookPath(\"go\")\n\tassert.NoError(t, err)\n\n\tcmd := exec.Command(goCMD, \"build\", filepath.Join(config.OutputDir, \"docs.go\"))\n\n\tcmd.Stdout = os.Stdout\n\n\tcmd.Stderr = os.Stderr\n\n\tassert.NoError(t, cmd.Run())\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.yaml\"),\n\t}\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\n\t\t_ = os.Remove(expectedFile)\n\t}\n}\n\nfunc TestGen_cgoImports(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          \"../testdata/simple_cgo\",\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple_cgo/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t\tParseDependency:    1,\n\t}\n\n\tassert.NoError(t, New().Build(config))\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.yaml\"),\n\t}\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\n\t\t_ = os.Remove(expectedFile)\n\t}\n}\n\nfunc TestGen_parseOverrides(t *testing.T) {\n\ttestCases := []struct {\n\t\tName          string\n\t\tData          string\n\t\tExpected      map[string]string\n\t\tExpectedError error\n\t}{\n\t\t{\n\t\t\tName: \"replace\",\n\t\t\tData: `replace github.com/foo/bar baz`,\n\t\t\tExpected: map[string]string{\n\t\t\t\t\"github.com/foo/bar\": \"baz\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"skip\",\n\t\t\tData: `skip github.com/foo/bar`,\n\t\t\tExpected: map[string]string{\n\t\t\t\t\"github.com/foo/bar\": \"\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"generic-simple\",\n\t\t\tData: `replace types.Field[string] string`,\n\t\t\tExpected: map[string]string{\n\t\t\t\t\"types.Field[string]\": \"string\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"generic-double\",\n\t\t\tData: `replace types.Field[string,string] string`,\n\t\t\tExpected: map[string]string{\n\t\t\t\t\"types.Field[string,string]\": \"string\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"comment\",\n\t\t\tData: `// this is a comment\n\t\t\treplace foo bar`,\n\t\t\tExpected: map[string]string{\n\t\t\t\t\"foo\": \"bar\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"ignore whitespace\",\n\t\t\tData: `\n\n\t\t\treplace foo bar`,\n\t\t\tExpected: map[string]string{\n\t\t\t\t\"foo\": \"bar\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:          \"unknown directive\",\n\t\t\tData:          `foo`,\n\t\t\tExpectedError: fmt.Errorf(\"could not parse override: 'foo'\"),\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\ttc := tc\n\t\tt.Run(tc.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\toverrides, err := parseOverrides(strings.NewReader(tc.Data))\n\t\t\tassert.Equal(t, tc.Expected, overrides)\n\t\t\tassert.Equal(t, tc.ExpectedError, err)\n\t\t})\n\t}\n}\n\nfunc TestGen_TypeOverridesFile(t *testing.T) {\n\tcustomPath := \"/foo/bar/baz\"\n\n\ttmp, err := os.CreateTemp(\"\", \"\")\n\trequire.NoError(t, err)\n\n\tdefer os.Remove(tmp.Name())\n\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple/docs\",\n\t\tPropNamingStrategy: \"\",\n\t}\n\n\tt.Run(\"Default file is missing\", func(t *testing.T) {\n\t\topen = func(path string) (*os.File, error) {\n\t\t\tassert.Equal(t, DefaultOverridesFile, path)\n\n\t\t\treturn nil, os.ErrNotExist\n\t\t}\n\t\tdefer func() {\n\t\t\topen = os.Open\n\t\t}()\n\n\t\tconfig.OverridesFile = DefaultOverridesFile\n\t\terr := New().Build(config)\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"Default file is present\", func(t *testing.T) {\n\t\topen = func(path string) (*os.File, error) {\n\t\t\tassert.Equal(t, DefaultOverridesFile, path)\n\n\t\t\treturn tmp, nil\n\t\t}\n\t\tdefer func() {\n\t\t\topen = os.Open\n\t\t}()\n\n\t\tconfig.OverridesFile = DefaultOverridesFile\n\t\terr := New().Build(config)\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"Different file is missing\", func(t *testing.T) {\n\t\topen = func(path string) (*os.File, error) {\n\t\t\tassert.Equal(t, customPath, path)\n\n\t\t\treturn nil, os.ErrNotExist\n\t\t}\n\t\tdefer func() {\n\t\t\topen = os.Open\n\t\t}()\n\n\t\tconfig.OverridesFile = customPath\n\t\terr := New().Build(config)\n\t\tassert.EqualError(t, err, \"could not open overrides file: file does not exist\")\n\t})\n\n\tt.Run(\"Different file is present\", func(t *testing.T) {\n\t\topen = func(path string) (*os.File, error) {\n\t\t\tassert.Equal(t, customPath, path)\n\n\t\t\treturn tmp, nil\n\t\t}\n\t\tdefer func() {\n\t\t\topen = os.Open\n\t\t}()\n\n\t\tconfig.OverridesFile = customPath\n\t\terr := New().Build(config)\n\t\tassert.NoError(t, err)\n\t})\n}\nfunc TestGen_Debugger(t *testing.T) {\n\tvar buf bytes.Buffer\n\tconfig := &Config{\n\t\tSearchDir:          searchDir,\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/simple/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t\tDebugger:           log.New(&buf, \"\", log.LstdFlags),\n\t}\n\tassert.True(t, buf.Len() == 0)\n\tassert.NoError(t, New().Build(config))\n\tassert.True(t, buf.Len() > 0)\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.yaml\"),\n\t}\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\n\t\t_ = os.Remove(expectedFile)\n\t}\n}\n\nfunc TestGen_ErrorAndInterface(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          \"../testdata/error\",\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/error/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t}\n\n\tassert.NoError(t, New().Build(config))\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"swagger.yaml\"),\n\t}\n\tt.Cleanup(func() {\n\t\tfor _, expectedFile := range expectedFiles {\n\t\t\t_ = os.Remove(expectedFile)\n\t\t}\n\t})\n\n\t// check files\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t}\n\n\t// check content\n\tjsonOutput, err := os.ReadFile(filepath.Join(config.OutputDir, \"swagger.json\"))\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\texpectedJSON, err := os.ReadFile(filepath.Join(config.SearchDir, \"expected.json\"))\n\tif err != nil {\n\t\trequire.NoError(t, err)\n\t}\n\n\tassert.JSONEq(t, string(expectedJSON), string(jsonOutput))\n}\n\nfunc TestGen_StateAdmin(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          \"../testdata/state\",\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/state/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t\tState:              \"admin\",\n\t}\n\n\tassert.NoError(t, New().Build(config))\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"admin_docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"admin_swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"admin_swagger.yaml\"),\n\t}\n\tt.Cleanup(func() {\n\t\tfor _, expectedFile := range expectedFiles {\n\t\t\t_ = os.Remove(expectedFile)\n\t\t}\n\t})\n\n\t// check files\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t}\n\n\t// check content\n\tjsonOutput, err := os.ReadFile(filepath.Join(config.OutputDir, \"admin_swagger.json\"))\n\trequire.NoError(t, err)\n\texpectedJSON, err := os.ReadFile(filepath.Join(config.SearchDir, \"admin_expected.json\"))\n\trequire.NoError(t, err)\n\n\tassert.JSONEq(t, string(expectedJSON), string(jsonOutput))\n}\n\nfunc TestGen_StateUser(t *testing.T) {\n\tconfig := &Config{\n\t\tSearchDir:          \"../testdata/state\",\n\t\tMainAPIFile:        \"./main.go\",\n\t\tOutputDir:          \"../testdata/state/docs\",\n\t\tOutputTypes:        outputTypes,\n\t\tPropNamingStrategy: \"\",\n\t\tState:              \"user\",\n\t}\n\n\tassert.NoError(t, New().Build(config))\n\n\texpectedFiles := []string{\n\t\tfilepath.Join(config.OutputDir, \"user_docs.go\"),\n\t\tfilepath.Join(config.OutputDir, \"user_swagger.json\"),\n\t\tfilepath.Join(config.OutputDir, \"user_swagger.yaml\"),\n\t}\n\tt.Cleanup(func() {\n\t\tfor _, expectedFile := range expectedFiles {\n\t\t\t_ = os.Remove(expectedFile)\n\t\t}\n\t})\n\n\t// check files\n\tfor _, expectedFile := range expectedFiles {\n\t\tif _, err := os.Stat(expectedFile); os.IsNotExist(err) {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t}\n\n\t// check content\n\tjsonOutput, err := os.ReadFile(filepath.Join(config.OutputDir, \"user_swagger.json\"))\n\trequire.NoError(t, err)\n\texpectedJSON, err := os.ReadFile(filepath.Join(config.SearchDir, \"user_expected.json\"))\n\trequire.NoError(t, err)\n\n\tassert.JSONEq(t, string(expectedJSON), string(jsonOutput))\n}\n"
  },
  {
    "path": "generics.go",
    "content": "package swag\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"go/ast\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/go-openapi/spec\"\n)\n\ntype genericTypeSpec struct {\n\tTypeSpec *TypeSpecDef\n\tName     string\n}\n\ntype formalParamType struct {\n\tName string\n\tType string\n}\n\nfunc (t *genericTypeSpec) TypeName() string {\n\tif t.TypeSpec != nil {\n\t\treturn t.TypeSpec.TypeName()\n\t}\n\treturn t.Name\n}\n\nfunc normalizeGenericTypeName(name string) string {\n\treturn strings.Replace(name, \".\", \"_\", -1)\n}\n\nfunc (pkgDefs *PackagesDefinitions) getTypeFromGenericParam(genericParam string, file *ast.File) (typeSpecDef *TypeSpecDef) {\n\tif strings.HasPrefix(genericParam, \"[]\") {\n\t\ttypeSpecDef = pkgDefs.getTypeFromGenericParam(genericParam[2:], file)\n\t\tif typeSpecDef == nil {\n\t\t\treturn nil\n\t\t}\n\t\tvar expr ast.Expr\n\t\tswitch typeSpecDef.TypeSpec.Type.(type) {\n\t\tcase *ast.ArrayType, *ast.MapType:\n\t\t\texpr = typeSpecDef.TypeSpec.Type\n\t\tdefault:\n\t\t\tname := typeSpecDef.TypeName()\n\t\t\texpr = ast.NewIdent(name)\n\t\t\tif _, ok := pkgDefs.uniqueDefinitions[name]; !ok {\n\t\t\t\tpkgDefs.uniqueDefinitions[name] = typeSpecDef\n\t\t\t}\n\t\t}\n\t\treturn &TypeSpecDef{\n\t\t\tTypeSpec: &ast.TypeSpec{\n\t\t\t\tName: ast.NewIdent(string(IgnoreNameOverridePrefix) + \"array_\" + typeSpecDef.TypeName()),\n\t\t\t\tType: &ast.ArrayType{\n\t\t\t\t\tElt: expr,\n\t\t\t\t},\n\t\t\t},\n\t\t\tEnums:      typeSpecDef.Enums,\n\t\t\tPkgPath:    typeSpecDef.PkgPath,\n\t\t\tParentSpec: typeSpecDef.ParentSpec,\n\t\t\tSchemaName: \"array_\" + typeSpecDef.SchemaName,\n\t\t\tNotUnique:  false,\n\t\t}\n\t}\n\n\tif strings.HasPrefix(genericParam, \"map[\") {\n\t\tparts := strings.SplitN(genericParam[4:], \"]\", 2)\n\t\tif len(parts) != 2 {\n\t\t\treturn nil\n\t\t}\n\t\ttypeSpecDef = pkgDefs.getTypeFromGenericParam(parts[1], file)\n\t\tif typeSpecDef == nil {\n\t\t\treturn nil\n\t\t}\n\t\tvar expr ast.Expr\n\t\tswitch typeSpecDef.TypeSpec.Type.(type) {\n\t\tcase *ast.ArrayType, *ast.MapType:\n\t\t\texpr = typeSpecDef.TypeSpec.Type\n\t\tdefault:\n\t\t\tname := typeSpecDef.TypeName()\n\t\t\texpr = ast.NewIdent(name)\n\t\t\tif _, ok := pkgDefs.uniqueDefinitions[name]; !ok {\n\t\t\t\tpkgDefs.uniqueDefinitions[name] = typeSpecDef\n\t\t\t}\n\t\t}\n\t\treturn &TypeSpecDef{\n\t\t\tTypeSpec: &ast.TypeSpec{\n\t\t\t\tName: ast.NewIdent(string(IgnoreNameOverridePrefix) + \"map_\" + parts[0] + \"_\" + typeSpecDef.TypeName()),\n\t\t\t\tType: &ast.MapType{\n\t\t\t\t\tKey:   ast.NewIdent(parts[0]), //assume key is string or integer\n\t\t\t\t\tValue: expr,\n\t\t\t\t},\n\t\t\t},\n\t\t\tEnums:      typeSpecDef.Enums,\n\t\t\tPkgPath:    typeSpecDef.PkgPath,\n\t\t\tParentSpec: typeSpecDef.ParentSpec,\n\t\t\tSchemaName: \"map_\" + parts[0] + \"_\" + typeSpecDef.SchemaName,\n\t\t\tNotUnique:  false,\n\t\t}\n\t}\n\tif IsGolangPrimitiveType(genericParam) {\n\t\treturn &TypeSpecDef{\n\t\t\tTypeSpec: &ast.TypeSpec{\n\t\t\t\tName: ast.NewIdent(genericParam),\n\t\t\t\tType: ast.NewIdent(genericParam),\n\t\t\t},\n\t\t\tSchemaName: genericParam,\n\t\t}\n\t}\n\treturn pkgDefs.FindTypeSpec(genericParam, file)\n}\n\nfunc (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, original *TypeSpecDef, fullGenericForm string) *TypeSpecDef {\n\tif original == nil || original.TypeSpec.TypeParams == nil || len(original.TypeSpec.TypeParams.List) == 0 {\n\t\treturn original\n\t}\n\n\tname, genericParams := splitGenericsTypeName(fullGenericForm)\n\tif genericParams == nil {\n\t\treturn nil\n\t}\n\n\t//generic[x,y any,z any] considered, TODO what if the type is not `any`, but a concrete one, such as `int32|int64` or an certain interface{}\n\tvar formals []formalParamType\n\tfor _, field := range original.TypeSpec.TypeParams.List {\n\t\tfor _, ident := range field.Names {\n\t\t\tformal := formalParamType{Name: ident.Name}\n\t\t\tif ident, ok := field.Type.(*ast.Ident); ok {\n\t\t\t\tformal.Type = ident.Name\n\t\t\t}\n\t\t\tformals = append(formals, formal)\n\t\t}\n\t}\n\tif len(genericParams) != len(formals) {\n\t\treturn nil\n\t}\n\tgenericParamTypeDefs := map[string]*genericTypeSpec{}\n\n\tfor i, genericParam := range genericParams {\n\t\tvar typeDef *TypeSpecDef\n\t\tif !IsGolangPrimitiveType(genericParam) {\n\t\t\ttypeDef = pkgDefs.getTypeFromGenericParam(genericParam, file)\n\t\t\tif typeDef != nil {\n\t\t\t\tgenericParam = typeDef.TypeName()\n\t\t\t\tif _, ok := pkgDefs.uniqueDefinitions[genericParam]; !ok {\n\t\t\t\t\tpkgDefs.uniqueDefinitions[genericParam] = typeDef\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tgenericParamTypeDefs[formals[i].Name] = &genericTypeSpec{\n\t\t\tTypeSpec: typeDef,\n\t\t\tName:     genericParam,\n\t\t}\n\t}\n\n\tname = fmt.Sprintf(\"%s%s-\", string(IgnoreNameOverridePrefix), original.TypeName())\n\tschemaName := fmt.Sprintf(\"%s-\", original.SchemaName)\n\n\tvar nameParts []string\n\tvar schemaNameParts []string\n\n\tfor _, def := range formals {\n\t\tif specDef, ok := genericParamTypeDefs[def.Name]; ok {\n\t\t\tnameParts = append(nameParts, specDef.Name)\n\n\t\t\tschemaNamePart := specDef.Name\n\n\t\t\tif specDef.TypeSpec != nil {\n\t\t\t\tschemaNamePart = specDef.TypeSpec.SchemaName\n\t\t\t}\n\n\t\t\tschemaNameParts = append(schemaNameParts, schemaNamePart)\n\t\t}\n\t}\n\n\tname += normalizeGenericTypeName(strings.Join(nameParts, \"-\"))\n\tschemaName += normalizeGenericTypeName(strings.Join(schemaNameParts, \"-\"))\n\n\tif typeSpec, ok := pkgDefs.uniqueDefinitions[name]; ok {\n\t\treturn typeSpec\n\t}\n\n\tparametrizedTypeSpec := &TypeSpecDef{\n\t\tFile:    original.File,\n\t\tPkgPath: original.PkgPath,\n\t\tEnums:   original.Enums,\n\t\tTypeSpec: &ast.TypeSpec{\n\t\t\tName: &ast.Ident{\n\t\t\t\tName:    name,\n\t\t\t\tNamePos: original.TypeSpec.Name.NamePos,\n\t\t\t\tObj:     original.TypeSpec.Name.Obj,\n\t\t\t},\n\t\t\tDoc:    original.TypeSpec.Doc,\n\t\t\tAssign: original.TypeSpec.Assign,\n\t\t},\n\t\tSchemaName: schemaName,\n\t}\n\tpkgDefs.uniqueDefinitions[name] = parametrizedTypeSpec\n\n\tparametrizedTypeSpec.TypeSpec.Type = pkgDefs.resolveGenericType(original.File, original.TypeSpec.Type, genericParamTypeDefs)\n\n\treturn parametrizedTypeSpec\n}\n\n// splitGenericsTypeName splits a generic struct name in his parts\nfunc splitGenericsTypeName(fullGenericForm string) (string, []string) {\n\t//remove all spaces character\n\tfullGenericForm = strings.Map(func(r rune) rune {\n\t\tif unicode.IsSpace(r) {\n\t\t\treturn -1\n\t\t}\n\t\treturn r\n\t}, fullGenericForm)\n\n\t// split only at the first '[' and remove the last ']'\n\tif fullGenericForm[len(fullGenericForm)-1] != ']' {\n\t\treturn \"\", nil\n\t}\n\n\tgenericParams := strings.SplitN(fullGenericForm[:len(fullGenericForm)-1], \"[\", 2)\n\tif len(genericParams) == 1 {\n\t\treturn \"\", nil\n\t}\n\n\t// generic type name\n\tgenericTypeName := genericParams[0]\n\n\tdepth := 0\n\tgenericParams = strings.FieldsFunc(genericParams[1], func(r rune) bool {\n\t\tif r == '[' {\n\t\t\tdepth++\n\t\t} else if r == ']' {\n\t\t\tdepth--\n\t\t} else if r == ',' && depth == 0 {\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t})\n\tif depth != 0 {\n\t\treturn \"\", nil\n\t}\n\n\treturn genericTypeName, genericParams\n}\n\nfunc (pkgDefs *PackagesDefinitions) getParametrizedType(genTypeSpec *genericTypeSpec) ast.Expr {\n\tif genTypeSpec.TypeSpec != nil && strings.Contains(genTypeSpec.Name, \".\") {\n\t\tparts := strings.SplitN(genTypeSpec.Name, \".\", 2)\n\t\treturn &ast.SelectorExpr{\n\t\t\tX:   &ast.Ident{Name: parts[0]},\n\t\t\tSel: &ast.Ident{Name: parts[1]},\n\t\t}\n\t}\n\n\t//a primitive type name or a type name in current package\n\treturn &ast.Ident{Name: genTypeSpec.Name}\n}\n\nfunc (pkgDefs *PackagesDefinitions) resolveGenericType(file *ast.File, expr ast.Expr, genericParamTypeDefs map[string]*genericTypeSpec) ast.Expr {\n\tswitch astExpr := expr.(type) {\n\tcase *ast.Ident:\n\t\tif genTypeSpec, ok := genericParamTypeDefs[astExpr.Name]; ok {\n\t\t\treturn pkgDefs.getParametrizedType(genTypeSpec)\n\t\t}\n\tcase *ast.ArrayType:\n\t\treturn &ast.ArrayType{\n\t\t\tElt:    pkgDefs.resolveGenericType(file, astExpr.Elt, genericParamTypeDefs),\n\t\t\tLen:    astExpr.Len,\n\t\t\tLbrack: astExpr.Lbrack,\n\t\t}\n\tcase *ast.MapType:\n\t\treturn &ast.MapType{\n\t\t\tMap:   astExpr.Map,\n\t\t\tKey:   pkgDefs.resolveGenericType(file, astExpr.Key, genericParamTypeDefs),\n\t\t\tValue: pkgDefs.resolveGenericType(file, astExpr.Value, genericParamTypeDefs),\n\t\t}\n\tcase *ast.StarExpr:\n\t\treturn &ast.StarExpr{\n\t\t\tStar: astExpr.Star,\n\t\t\tX:    pkgDefs.resolveGenericType(file, astExpr.X, genericParamTypeDefs),\n\t\t}\n\tcase *ast.IndexExpr, *ast.IndexListExpr:\n\t\tfullGenericName, _ := getGenericFieldType(file, expr, genericParamTypeDefs)\n\t\ttypeDef := pkgDefs.FindTypeSpec(fullGenericName, file)\n\t\tif typeDef != nil {\n\t\t\treturn typeDef.TypeSpec.Name\n\t\t}\n\tcase *ast.StructType:\n\t\tnewStructTypeDef := &ast.StructType{\n\t\t\tStruct:     astExpr.Struct,\n\t\t\tIncomplete: astExpr.Incomplete,\n\t\t\tFields: &ast.FieldList{\n\t\t\t\tOpening: astExpr.Fields.Opening,\n\t\t\t\tClosing: astExpr.Fields.Closing,\n\t\t\t},\n\t\t}\n\n\t\tfor _, field := range astExpr.Fields.List {\n\t\t\tnewField := &ast.Field{\n\t\t\t\tType:    field.Type,\n\t\t\t\tDoc:     field.Doc,\n\t\t\t\tNames:   field.Names,\n\t\t\t\tTag:     field.Tag,\n\t\t\t\tComment: field.Comment,\n\t\t\t}\n\n\t\t\tnewField.Type = pkgDefs.resolveGenericType(file, field.Type, genericParamTypeDefs)\n\n\t\t\tnewStructTypeDef.Fields.List = append(newStructTypeDef.Fields.List, newField)\n\t\t}\n\t\treturn newStructTypeDef\n\t}\n\treturn expr\n}\n\nfunc getExtendedGenericFieldType(file *ast.File, field ast.Expr, genericParamTypeDefs map[string]*genericTypeSpec) (string, error) {\n\tswitch fieldType := field.(type) {\n\tcase *ast.ArrayType:\n\t\tfieldName, err := getExtendedGenericFieldType(file, fieldType.Elt, genericParamTypeDefs)\n\t\treturn \"[]\" + fieldName, err\n\tcase *ast.StarExpr:\n\t\treturn getExtendedGenericFieldType(file, fieldType.X, genericParamTypeDefs)\n\tcase *ast.Ident:\n\t\tif genericParamTypeDefs != nil {\n\t\t\tif typeSpec, ok := genericParamTypeDefs[fieldType.Name]; ok {\n\t\t\t\treturn typeSpec.Name, nil\n\t\t\t}\n\t\t}\n\t\tif fieldType.Obj == nil {\n\t\t\treturn fieldType.Name, nil\n\t\t}\n\n\t\ttSpec := &TypeSpecDef{\n\t\t\tFile:     file,\n\t\t\tTypeSpec: fieldType.Obj.Decl.(*ast.TypeSpec),\n\t\t\tPkgPath:  file.Name.Name,\n\t\t}\n\t\treturn tSpec.TypeName(), nil\n\tdefault:\n\t\treturn getFieldType(file, field, genericParamTypeDefs)\n\t}\n}\n\nfunc getGenericFieldType(file *ast.File, field ast.Expr, genericParamTypeDefs map[string]*genericTypeSpec) (string, error) {\n\tvar fullName string\n\tvar baseName string\n\tvar err error\n\tswitch fieldType := field.(type) {\n\tcase *ast.IndexListExpr:\n\t\tbaseName, err = getGenericTypeName(file, fieldType.X)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tfullName = baseName + \"[\"\n\n\t\tfor _, index := range fieldType.Indices {\n\t\t\tfieldName, err := getExtendedGenericFieldType(file, index, genericParamTypeDefs)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\n\t\t\tfullName += fieldName + \",\"\n\t\t}\n\n\t\tfullName = strings.TrimRight(fullName, \",\") + \"]\"\n\tcase *ast.IndexExpr:\n\t\tbaseName, err = getGenericTypeName(file, fieldType.X)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tindexName, err := getExtendedGenericFieldType(file, fieldType.Index, genericParamTypeDefs)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tfullName = fmt.Sprintf(\"%s[%s]\", baseName, indexName)\n\t}\n\n\tif fullName == \"\" {\n\t\treturn \"\", fmt.Errorf(\"unknown field type %#v\", field)\n\t}\n\n\tvar packageName string\n\tif !strings.Contains(baseName, \".\") {\n\t\tif file.Name == nil {\n\t\t\treturn \"\", errors.New(\"file name is nil\")\n\t\t}\n\t\tpackageName, _ = getFieldType(file, file.Name, genericParamTypeDefs)\n\t}\n\n\treturn strings.TrimLeft(fmt.Sprintf(\"%s.%s\", packageName, fullName), \".\"), nil\n}\n\nfunc getGenericTypeName(file *ast.File, field ast.Expr) (string, error) {\n\tswitch fieldType := field.(type) {\n\tcase *ast.Ident:\n\t\tif fieldType.Obj == nil {\n\t\t\treturn fieldType.Name, nil\n\t\t}\n\n\t\ttSpec := &TypeSpecDef{\n\t\t\tFile:     file,\n\t\t\tTypeSpec: fieldType.Obj.Decl.(*ast.TypeSpec),\n\t\t\tPkgPath:  file.Name.Name,\n\t\t}\n\t\treturn tSpec.TypeName(), nil\n\tcase *ast.ArrayType:\n\t\ttSpec := &TypeSpecDef{\n\t\t\tFile:     file,\n\t\t\tTypeSpec: fieldType.Elt.(*ast.Ident).Obj.Decl.(*ast.TypeSpec),\n\t\t\tPkgPath:  file.Name.Name,\n\t\t}\n\t\treturn tSpec.TypeName(), nil\n\tcase *ast.SelectorExpr:\n\t\treturn fmt.Sprintf(\"%s.%s\", fieldType.X.(*ast.Ident).Name, fieldType.Sel.Name), nil\n\t}\n\treturn \"\", fmt.Errorf(\"unknown type %#v\", field)\n}\n\nfunc (parser *Parser) parseGenericTypeExpr(file *ast.File, typeExpr ast.Expr) (*spec.Schema, error) {\n\tswitch expr := typeExpr.(type) {\n\t// suppress debug messages for these types\n\tcase *ast.InterfaceType:\n\tcase *ast.StructType:\n\tcase *ast.Ident:\n\tcase *ast.StarExpr:\n\tcase *ast.SelectorExpr:\n\tcase *ast.ArrayType:\n\tcase *ast.MapType:\n\tcase *ast.FuncType:\n\tcase *ast.IndexExpr, *ast.IndexListExpr:\n\t\tname, err := getExtendedGenericFieldType(file, expr, nil)\n\t\tif err == nil {\n\t\t\tif schema, err := parser.getTypeSchema(name, file, false); err == nil {\n\t\t\t\treturn schema, nil\n\t\t\t}\n\t\t}\n\n\t\tparser.debug.Printf(\"Type definition of type '%T' is not supported yet. Using 'object' instead. (%s)\\n\", typeExpr, err)\n\tdefault:\n\t\tparser.debug.Printf(\"Type definition of type '%T' is not supported yet. Using 'object' instead.\\n\", typeExpr)\n\t}\n\n\treturn PrimitiveSchema(OBJECT), nil\n}\n"
  },
  {
    "path": "generics_test.go",
    "content": "package swag\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"go/ast\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype testLogger struct {\n\tMessages []string\n}\n\nfunc (t *testLogger) Printf(format string, v ...interface{}) {\n\tt.Messages = append(t.Messages, fmt.Sprintf(format, v...))\n}\n\nfunc TestParseGenericsBasic(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/generics_basic\"\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tp := New()\n\tp.Overrides = map[string]string{\n\t\t\"types.Field[string]\":               \"string\",\n\t\t\"types.DoubleField[string,string]\":  \"[]string\",\n\t\t\"types.TrippleField[string,string]\": \"[][]string\",\n\t}\n\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, err := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseGenericsArrays(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/generics_arrays\"\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tp := New()\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, err := json.MarshalIndent(p.swagger, \"\", \"    \")\n\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseGenericsNested(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/generics_nested\"\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tp := New()\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, err := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseGenericsMultiLevelNesting(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/generics_multi_level_nesting\"\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tp := New()\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, err := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseGenericsProperty(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/generics_property\"\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tp := New()\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, err := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseGenericsNames(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/generics_names\"\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tp := New()\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, err := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseGenericsPackageAlias(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/generics_package_alias/internal\"\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tp := New(SetParseDependency(1))\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, err := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseGenericsFunctionScoped(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/generics_function_scoped\"\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tp := New()\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, err := json.MarshalIndent(p.swagger, \"\", \"    \")\n\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParametrizeStruct(t *testing.T) {\n\tpd := PackagesDefinitions{\n\t\tpackages:          make(map[string]*PackageDefinitions),\n\t\tuniqueDefinitions: make(map[string]*TypeSpecDef),\n\t}\n\t// valid\n\ttypeSpec := pd.parametrizeGenericType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test2\"}},\n\t\t&TypeSpecDef{\n\t\t\tFile: &ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t\tTypeSpec: &ast.TypeSpec{\n\t\t\t\tName:       &ast.Ident{Name: \"Field\"},\n\t\t\t\tTypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: \"T\"}}}, {Names: []*ast.Ident{{Name: \"T2\"}}}}},\n\t\t\t\tType:       &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},\n\t\t\t}}, \"test.Field[string, []string]\")\n\tassert.NotNil(t, typeSpec)\n\tassert.Equal(t, \"$test.Field-string-array_string\", typeSpec.Name())\n\tassert.Equal(t, \"test.Field-string-array_string\", typeSpec.TypeName())\n\n\t// definition contains one type params, but two type params are provided\n\ttypeSpec = pd.parametrizeGenericType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test2\"}},\n\t\t&TypeSpecDef{\n\t\t\tTypeSpec: &ast.TypeSpec{\n\t\t\t\tName:       &ast.Ident{Name: \"Field\"},\n\t\t\t\tTypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: \"T\"}}}}},\n\t\t\t\tType:       &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},\n\t\t\t}}, \"test.Field[string, string]\")\n\tassert.Nil(t, typeSpec)\n\n\t// definition contains two type params, but only one is used\n\ttypeSpec = pd.parametrizeGenericType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test2\"}},\n\t\t&TypeSpecDef{\n\t\t\tTypeSpec: &ast.TypeSpec{\n\t\t\t\tName:       &ast.Ident{Name: \"Field\"},\n\t\t\t\tTypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: \"T\"}}}, {Names: []*ast.Ident{{Name: \"T2\"}}}}},\n\t\t\t\tType:       &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},\n\t\t\t}}, \"test.Field[string]\")\n\tassert.Nil(t, typeSpec)\n\n\t// name is not a valid type name\n\ttypeSpec = pd.parametrizeGenericType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test2\"}},\n\t\t&TypeSpecDef{\n\t\t\tTypeSpec: &ast.TypeSpec{\n\t\t\t\tName:       &ast.Ident{Name: \"Field\"},\n\t\t\t\tTypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: \"T\"}}}, {Names: []*ast.Ident{{Name: \"T2\"}}}}},\n\t\t\t\tType:       &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},\n\t\t\t}}, \"test.Field[string\")\n\tassert.Nil(t, typeSpec)\n\n\ttypeSpec = pd.parametrizeGenericType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test2\"}},\n\t\t&TypeSpecDef{\n\t\t\tTypeSpec: &ast.TypeSpec{\n\t\t\t\tName:       &ast.Ident{Name: \"Field\"},\n\t\t\t\tTypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: \"T\"}}}, {Names: []*ast.Ident{{Name: \"T2\"}}}}},\n\t\t\t\tType:       &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},\n\t\t\t}}, \"test.Field[string, [string]\")\n\tassert.Nil(t, typeSpec)\n\n\ttypeSpec = pd.parametrizeGenericType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test2\"}},\n\t\t&TypeSpecDef{\n\t\t\tTypeSpec: &ast.TypeSpec{\n\t\t\t\tName:       &ast.Ident{Name: \"Field\"},\n\t\t\t\tTypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: \"T\"}}}, {Names: []*ast.Ident{{Name: \"T2\"}}}}},\n\t\t\t\tType:       &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},\n\t\t\t}}, \"test.Field[string, ]string]\")\n\tassert.Nil(t, typeSpec)\n}\n\nfunc TestSplitGenericsTypeNames(t *testing.T) {\n\tt.Parallel()\n\n\tfield, params := splitGenericsTypeName(\"test.Field\")\n\tassert.Empty(t, field)\n\tassert.Nil(t, params)\n\n\tfield, params = splitGenericsTypeName(\"test.Field]\")\n\tassert.Empty(t, field)\n\tassert.Nil(t, params)\n\n\tfield, params = splitGenericsTypeName(\"test.Field[string\")\n\tassert.Empty(t, field)\n\tassert.Nil(t, params)\n\n\tfield, params = splitGenericsTypeName(\"test.Field[string] \")\n\tassert.Equal(t, \"test.Field\", field)\n\tassert.Equal(t, []string{\"string\"}, params)\n\n\tfield, params = splitGenericsTypeName(\"test.Field[string, []string]\")\n\tassert.Equal(t, \"test.Field\", field)\n\tassert.Equal(t, []string{\"string\", \"[]string\"}, params)\n\n\tfield, params = splitGenericsTypeName(\"test.Field[test.Field[ string, []string] ]\")\n\tassert.Equal(t, \"test.Field\", field)\n\tassert.Equal(t, []string{\"test.Field[string,[]string]\"}, params)\n}\n\nfunc TestGetGenericFieldType(t *testing.T) {\n\tfield, err := getFieldType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.IndexListExpr{\n\t\t\tX:       &ast.Ident{Name: \"types\", Obj: &ast.Object{Decl: &ast.TypeSpec{Name: &ast.Ident{Name: \"Field\"}}}},\n\t\t\tIndices: []ast.Expr{&ast.Ident{Name: \"string\"}},\n\t\t},\n\t\tnil,\n\t)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"test.Field[string]\", field)\n\n\tfield, err = getFieldType(\n\t\t&ast.File{Name: &ast.Ident{}},\n\t\t&ast.IndexListExpr{\n\t\t\tX:       &ast.Ident{Name: \"types\", Obj: &ast.Object{Decl: &ast.TypeSpec{Name: &ast.Ident{Name: \"Field\"}}}},\n\t\t\tIndices: []ast.Expr{&ast.Ident{Name: \"string\"}},\n\t\t},\n\t\tnil,\n\t)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"Field[string]\", field)\n\n\tfield, err = getFieldType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.IndexListExpr{\n\t\t\tX:       &ast.Ident{Name: \"types\", Obj: &ast.Object{Decl: &ast.TypeSpec{Name: &ast.Ident{Name: \"Field\"}}}},\n\t\t\tIndices: []ast.Expr{&ast.Ident{Name: \"string\"}, &ast.Ident{Name: \"int\"}},\n\t\t},\n\t\tnil,\n\t)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"test.Field[string,int]\", field)\n\n\tfield, err = getFieldType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.IndexListExpr{\n\t\t\tX:       &ast.Ident{Name: \"types\", Obj: &ast.Object{Decl: &ast.TypeSpec{Name: &ast.Ident{Name: \"Field\"}}}},\n\t\t\tIndices: []ast.Expr{&ast.Ident{Name: \"string\"}, &ast.ArrayType{Elt: &ast.Ident{Name: \"int\"}}},\n\t\t},\n\t\tnil,\n\t)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"test.Field[string,[]int]\", field)\n\n\tfield, err = getFieldType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.IndexListExpr{\n\t\t\tX:       &ast.BadExpr{},\n\t\t\tIndices: []ast.Expr{&ast.Ident{Name: \"string\"}, &ast.Ident{Name: \"int\"}},\n\t\t},\n\t\tnil,\n\t)\n\tassert.Error(t, err)\n\n\tfield, err = getFieldType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.IndexListExpr{\n\t\t\tX:       &ast.Ident{Name: \"types\", Obj: &ast.Object{Decl: &ast.TypeSpec{Name: &ast.Ident{Name: \"Field\"}}}},\n\t\t\tIndices: []ast.Expr{&ast.Ident{Name: \"string\"}, &ast.ArrayType{Elt: &ast.BadExpr{}}},\n\t\t},\n\t\tnil,\n\t)\n\tassert.Error(t, err)\n\n\tfield, err = getFieldType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.IndexExpr{X: &ast.Ident{Name: \"Field\"}, Index: &ast.Ident{Name: \"string\"}},\n\t\tnil,\n\t)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"test.Field[string]\", field)\n\n\tfield, err = getFieldType(\n\t\t&ast.File{Name: nil},\n\t\t&ast.IndexExpr{X: &ast.Ident{Name: \"Field\"}, Index: &ast.Ident{Name: \"string\"}},\n\t\tnil,\n\t)\n\tassert.Error(t, err)\n\n\tfield, err = getFieldType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.IndexExpr{X: &ast.BadExpr{}, Index: &ast.Ident{Name: \"string\"}},\n\t\tnil,\n\t)\n\tassert.Error(t, err)\n\n\tfield, err = getFieldType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.IndexExpr{X: &ast.Ident{Name: \"Field\"}, Index: &ast.BadExpr{}},\n\t\tnil,\n\t)\n\tassert.Error(t, err)\n\n\tfield, err = getFieldType(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.IndexExpr{X: &ast.SelectorExpr{X: &ast.Ident{Name: \"field\"}, Sel: &ast.Ident{Name: \"Name\"}}, Index: &ast.Ident{Name: \"string\"}},\n\t\tnil,\n\t)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"field.Name[string]\", field)\n}\n\nfunc TestGetGenericTypeName(t *testing.T) {\n\tfield, err := getGenericTypeName(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.Ident{Name: \"types\", Obj: &ast.Object{Decl: &ast.TypeSpec{Name: &ast.Ident{Name: \"Field\"}}}},\n\t)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"test.Field\", field)\n\n\tfield, err = getGenericTypeName(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.ArrayType{Elt: &ast.Ident{Name: \"types\", Obj: &ast.Object{Decl: &ast.TypeSpec{Name: &ast.Ident{Name: \"Field\"}}}}},\n\t)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"test.Field\", field)\n\n\tfield, err = getGenericTypeName(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.SelectorExpr{X: &ast.Ident{Name: \"field\"}, Sel: &ast.Ident{Name: \"Name\"}},\n\t)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"field.Name\", field)\n\n\t_, err = getGenericTypeName(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.BadExpr{},\n\t)\n\tassert.Error(t, err)\n}\n\nfunc TestParseGenericTypeExpr(t *testing.T) {\n\tt.Parallel()\n\n\tparser := New()\n\tlogger := &testLogger{}\n\tSetDebugger(logger)(parser)\n\n\t_, _ = parser.parseGenericTypeExpr(&ast.File{}, &ast.InterfaceType{})\n\tassert.Empty(t, logger.Messages)\n\t_, _ = parser.parseGenericTypeExpr(&ast.File{}, &ast.StructType{})\n\tassert.Empty(t, logger.Messages)\n\t_, _ = parser.parseGenericTypeExpr(&ast.File{}, &ast.Ident{})\n\tassert.Empty(t, logger.Messages)\n\t_, _ = parser.parseGenericTypeExpr(&ast.File{}, &ast.StarExpr{})\n\tassert.Empty(t, logger.Messages)\n\t_, _ = parser.parseGenericTypeExpr(&ast.File{}, &ast.SelectorExpr{})\n\tassert.Empty(t, logger.Messages)\n\t_, _ = parser.parseGenericTypeExpr(&ast.File{}, &ast.ArrayType{})\n\tassert.Empty(t, logger.Messages)\n\t_, _ = parser.parseGenericTypeExpr(&ast.File{}, &ast.MapType{})\n\tassert.Empty(t, logger.Messages)\n\t_, _ = parser.parseGenericTypeExpr(&ast.File{}, &ast.FuncType{})\n\tassert.Empty(t, logger.Messages)\n\t_, _ = parser.parseGenericTypeExpr(&ast.File{}, &ast.BadExpr{})\n\tassert.NotEmpty(t, logger.Messages)\n\tassert.Len(t, logger.Messages, 1)\n\n\tparser.packages.uniqueDefinitions[\"field.Name[string]\"] = &TypeSpecDef{\n\t\tFile: &ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\tTypeSpec: &ast.TypeSpec{\n\t\t\tName:       &ast.Ident{Name: \"Field\"},\n\t\t\tTypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: \"T\"}}}}},\n\t\t\tType:       &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},\n\t\t},\n\t}\n\tspec, err := parser.parseTypeExpr(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.IndexExpr{X: &ast.SelectorExpr{X: &ast.Ident{Name: \"field\"}, Sel: &ast.Ident{Name: \"Name\"}}, Index: &ast.Ident{Name: \"string\"}},\n\t\tfalse,\n\t)\n\tassert.NotNil(t, spec)\n\tassert.NoError(t, err)\n\n\tlogger.Messages = []string{}\n\tspec, err = parser.parseTypeExpr(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.IndexExpr{X: &ast.BadExpr{}, Index: &ast.Ident{Name: \"string\"}},\n\t\tfalse,\n\t)\n\tassert.NotNil(t, spec)\n\tassert.Equal(t, \"object\", spec.SchemaProps.Type[0])\n\tassert.NotEmpty(t, logger.Messages)\n\tassert.Len(t, logger.Messages, 1)\n\n\tlogger.Messages = []string{}\n\tspec, err = parser.parseTypeExpr(\n\t\t&ast.File{Name: &ast.Ident{Name: \"test\"}},\n\t\t&ast.BadExpr{},\n\t\tfalse,\n\t)\n\tassert.NotNil(t, spec)\n\tassert.Equal(t, \"object\", spec.SchemaProps.Type[0])\n\tassert.NotEmpty(t, logger.Messages)\n\tassert.Len(t, logger.Messages, 1)\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/swaggo/swag\n\ngo 1.24.0\n\nrequire (\n\tgithub.com/KyleBanks/depth v1.2.1\n\tgithub.com/go-openapi/spec v0.22.1\n\tgithub.com/stretchr/testify v1.11.1\n\tgithub.com/urfave/cli/v2 v2.3.0\n\tgolang.org/x/sync v0.12.0\n\tgolang.org/x/text v0.23.0\n\tgolang.org/x/tools v0.26.0\n\tsigs.k8s.io/yaml v1.3.0\n)\n\nrequire (\n\tgithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/go-openapi/jsonpointer v0.22.1 // indirect\n\tgithub.com/go-openapi/jsonreference v0.21.3 // indirect\n\tgithub.com/go-openapi/swag/conv v0.25.1 // indirect\n\tgithub.com/go-openapi/swag/jsonname v0.25.1 // indirect\n\tgithub.com/go-openapi/swag/jsonutils v0.25.1 // indirect\n\tgithub.com/go-openapi/swag/loading v0.25.1 // indirect\n\tgithub.com/go-openapi/swag/stringutils v0.25.1 // indirect\n\tgithub.com/go-openapi/swag/typeutils v0.25.1 // indirect\n\tgithub.com/go-openapi/swag/yamlutils v0.25.1 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/russross/blackfriday/v2 v2.0.1 // indirect\n\tgithub.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect\n\tgo.yaml.in/yaml/v3 v3.0.4 // indirect\n\tgolang.org/x/mod v0.21.0 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nretract (\n\tv1.16.0 // published accidentally\n\tv1.9.0 // published accidentally\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=\ngithub.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk=\ngithub.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM=\ngithub.com/go-openapi/jsonreference v0.21.3 h1:96Dn+MRPa0nYAR8DR1E03SblB5FJvh7W6krPI0Z7qMc=\ngithub.com/go-openapi/jsonreference v0.21.3/go.mod h1:RqkUP0MrLf37HqxZxrIAtTWW4ZJIK1VzduhXYBEeGc4=\ngithub.com/go-openapi/spec v0.22.1 h1:beZMa5AVQzRspNjvhe5aG1/XyBSMeX1eEOs7dMoXh/k=\ngithub.com/go-openapi/spec v0.22.1/go.mod h1:c7aeIQT175dVowfp7FeCvXXnjN/MrpaONStibD2WtDA=\ngithub.com/go-openapi/swag/conv v0.25.1 h1:+9o8YUg6QuqqBM5X6rYL/p1dpWeZRhoIt9x7CCP+he0=\ngithub.com/go-openapi/swag/conv v0.25.1/go.mod h1:Z1mFEGPfyIKPu0806khI3zF+/EUXde+fdeksUl2NiDs=\ngithub.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU=\ngithub.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo=\ngithub.com/go-openapi/swag/jsonutils v0.25.1 h1:AihLHaD0brrkJoMqEZOBNzTLnk81Kg9cWr+SPtxtgl8=\ngithub.com/go-openapi/swag/jsonutils v0.25.1/go.mod h1:JpEkAjxQXpiaHmRO04N1zE4qbUEg3b7Udll7AMGTNOo=\ngithub.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1 h1:DSQGcdB6G0N9c/KhtpYc71PzzGEIc/fZ1no35x4/XBY=\ngithub.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1/go.mod h1:kjmweouyPwRUEYMSrbAidoLMGeJ5p6zdHi9BgZiqmsg=\ngithub.com/go-openapi/swag/loading v0.25.1 h1:6OruqzjWoJyanZOim58iG2vj934TysYVptyaoXS24kw=\ngithub.com/go-openapi/swag/loading v0.25.1/go.mod h1:xoIe2EG32NOYYbqxvXgPzne989bWvSNoWoyQVWEZicc=\ngithub.com/go-openapi/swag/stringutils v0.25.1 h1:Xasqgjvk30eUe8VKdmyzKtjkVjeiXx1Iz0zDfMNpPbw=\ngithub.com/go-openapi/swag/stringutils v0.25.1/go.mod h1:JLdSAq5169HaiDUbTvArA2yQxmgn4D6h4A+4HqVvAYg=\ngithub.com/go-openapi/swag/typeutils v0.25.1 h1:rD/9HsEQieewNt6/k+JBwkxuAHktFtH3I3ysiFZqukA=\ngithub.com/go-openapi/swag/typeutils v0.25.1/go.mod h1:9McMC/oCdS4BKwk2shEB7x17P6HmMmA6dQRtAkSnNb8=\ngithub.com/go-openapi/swag/yamlutils v0.25.1 h1:mry5ez8joJwzvMbaTGLhw8pXUnhDK91oSJLDPF1bmGk=\ngithub.com/go-openapi/swag/yamlutils v0.25.1/go.mod h1:cm9ywbzncy3y6uPm/97ysW8+wZ09qsks+9RS8fLWKqg=\ngithub.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=\ngithub.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=\ngithub.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=\ngithub.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=\ngithub.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=\ngo.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=\ngo.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=\ngolang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=\ngolang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=\ngolang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=\ngolang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=\ngolang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=\ngolang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=\ngolang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=\ngolang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nsigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=\nsigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=\n"
  },
  {
    "path": "golist.go",
    "content": "package swag\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"go/build\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"slices\"\n)\n\nfunc listPackages(ctx context.Context, dirs []string, env []string, args ...string) ([]*build.Package, error) {\n\tpkgMap := make(map[string]*build.Package)\n\tfor i, dir := range dirs {\n\t\tpkgs, err := listOnePackages(ctx, dir, env, args...)\n\t\tif err != nil {\n\t\t\tif i == 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"pkg %s cannot find all dependencies, %s\", dir, err)\n\t\t\t}\n\t\t\tcontinue // ignore search dir load error?\n\t\t}\n\t\tfor _, pkg := range pkgs {\n\t\t\tpkgMap[pkg.Dir] = pkg\n\t\t}\n\t}\n\tpkgs := make([]*build.Package, 0, len(pkgMap))\n\tfor _, pkg := range pkgMap {\n\t\tpkgs = append(pkgs, pkg)\n\t}\n\tslices.SortFunc(pkgs, func(a, b *build.Package) int {\n\t\tif a.Dir < b.Dir {\n\t\t\treturn -1\n\t\t} else if a.Dir > b.Dir {\n\t\t\treturn 1\n\t\t}\n\t\treturn 0\n\t})\n\treturn pkgs, nil\n}\n\nfunc listOnePackages(ctx context.Context, dir string, env []string, args ...string) (pkgs []*build.Package, finalErr error) {\n\tcmd := exec.CommandContext(ctx, \"go\", append([]string{\"list\", \"-json\", \"-e\"}, args...)...)\n\tcmd.Env = env\n\tcmd.Dir = dir\n\n\tstdout, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar stderrBuf bytes.Buffer\n\tcmd.Stderr = &stderrBuf\n\tdefer func() {\n\t\tif (finalErr != nil) && (stderrBuf.Len() > 0) {\n\t\t\tfinalErr = fmt.Errorf(\"%v\\n%s\", finalErr, stderrBuf.Bytes())\n\t\t}\n\t}()\n\n\terr = cmd.Start()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdec := json.NewDecoder(stdout)\n\tfor dec.More() {\n\t\tvar pkg build.Package\n\t\terr = dec.Decode(&pkg)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpkgs = append(pkgs, &pkg)\n\t}\n\terr = cmd.Wait()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn pkgs, nil\n}\n\nfunc (parser *Parser) getAllGoFileInfoFromDepsByList(pkg *build.Package, parseFlag ParseFlag) error {\n\tignoreInternal := pkg.Goroot && !parser.ParseInternal\n\tif ignoreInternal { // ignored internal\n\t\treturn nil\n\t}\n\n\tif parser.skipPackageByPrefix(pkg.ImportPath) {\n\t\treturn nil // ignored by user-defined package path prefixes\n\t}\n\n\tsrcDir := pkg.Dir\n\tvar err error\n\tfor i := range pkg.GoFiles {\n\t\terr = parser.parseFile(pkg.ImportPath, filepath.Join(srcDir, pkg.GoFiles[i]), nil, parseFlag)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// parse .go source files that import \"C\"\n\tfor i := range pkg.CgoFiles {\n\t\terr = parser.parseFile(pkg.ImportPath, filepath.Join(srcDir, pkg.CgoFiles[i]), nil, parseFlag)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "golist_test.go",
    "content": "package swag\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"go/build\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestListPackages(t *testing.T) {\n\n\tcases := []struct {\n\t\tname      string\n\t\targs      []string\n\t\tsearchDir string\n\t\texcept    error\n\t}{\n\t\t{\n\t\t\tname:      \"errorArgs\",\n\t\t\targs:      []string{\"-abc\"},\n\t\t\tsearchDir: \"testdata/golist\",\n\t\t\texcept:    fmt.Errorf(\"exit status 2\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"normal\",\n\t\t\targs:      []string{\"-deps\"},\n\t\t\tsearchDir: \"testdata/golist\",\n\t\t\texcept:    nil,\n\t\t},\n\t\t{\n\t\t\tname:      \"list error\",\n\t\t\targs:      []string{\"-deps\"},\n\t\t\tsearchDir: \"testdata/golist_not_exist\",\n\t\t\texcept:    errors.New(\"searchDir not exist\"),\n\t\t},\n\t}\n\n\tfor _, c := range cases {\n\t\tt.Run(c.name, func(t *testing.T) {\n\t\t\t_, err := listOnePackages(context.TODO(), c.searchDir, nil, c.args...)\n\t\t\tif c.except != nil {\n\t\t\t\tassert.NotNil(t, err)\n\t\t\t} else {\n\t\t\t\tassert.Nil(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetAllGoFileInfoFromDepsByList(t *testing.T) {\n\tp := New(ParseUsingGoList(true))\n\tpwd, err := os.Getwd()\n\tassert.NoError(t, err)\n\tcases := []struct {\n\t\tname           string\n\t\tbuildPackage   *build.Package\n\t\tignoreInternal bool\n\t\texcept         error\n\t}{\n\t\t{\n\t\t\tname: \"normal\",\n\t\t\tbuildPackage: &build.Package{\n\t\t\t\tName:       \"main\",\n\t\t\t\tImportPath: \"github.com/swaggo/swag/testdata/golist\",\n\t\t\t\tDir:        \"testdata/golist\",\n\t\t\t\tGoFiles:    []string{\"main.go\"},\n\t\t\t\tCgoFiles:   []string{\"api/api.go\"},\n\t\t\t},\n\t\t\texcept: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"ignore internal\",\n\t\t\tbuildPackage: &build.Package{\n\t\t\t\tGoroot: true,\n\t\t\t},\n\t\t\tignoreInternal: true,\n\t\t\texcept:         nil,\n\t\t},\n\t\t{\n\t\t\tname: \"gofiles error\",\n\t\t\tbuildPackage: &build.Package{\n\t\t\t\tDir:     \"testdata/golist_not_exist\",\n\t\t\t\tGoFiles: []string{\"main.go\"},\n\t\t\t},\n\t\t\texcept: errors.New(\"file not exist\"),\n\t\t},\n\t\t{\n\t\t\tname: \"cgofiles error\",\n\t\t\tbuildPackage: &build.Package{\n\t\t\t\tDir:      \"testdata/golist_not_exist\",\n\t\t\t\tCgoFiles: []string{\"main.go\"},\n\t\t\t},\n\t\t\texcept: errors.New(\"file not exist\"),\n\t\t},\n\t}\n\n\tfor _, c := range cases {\n\t\tt.Run(c.name, func(t *testing.T) {\n\t\t\tif c.ignoreInternal {\n\t\t\t\tp.ParseInternal = false\n\t\t\t}\n\t\t\tc.buildPackage.Dir = filepath.Join(pwd, c.buildPackage.Dir)\n\t\t\terr := p.getAllGoFileInfoFromDepsByList(c.buildPackage, ParseModels)\n\t\t\tif c.except != nil {\n\t\t\t\tassert.NotNil(t, err)\n\t\t\t} else {\n\t\t\t\tassert.Nil(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "license",
    "content": "MIT License\n\nCopyright (c) 2017 Eason Lin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "operation.go",
    "content": "package swag\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"go/ast\"\n\tgoparser \"go/parser\"\n\t\"go/token\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/go-openapi/spec\"\n\t\"golang.org/x/tools/go/loader\"\n)\n\n// RouteProperties describes HTTP properties of a single router comment.\ntype RouteProperties struct {\n\tHTTPMethod string\n\tPath       string\n\tDeprecated bool\n}\n\n// Operation describes a single API operation on a path.\n// For more information: https://github.com/swaggo/swag#api-operation\ntype Operation struct {\n\tparser              *Parser\n\tcodeExampleFilesDir string\n\tspec.Operation\n\tRouterProperties []RouteProperties\n\tState            string\n}\n\nvar mimeTypeAliases = map[string]string{\n\t\"json\":                  \"application/json\",\n\t\"xml\":                   \"text/xml\",\n\t\"plain\":                 \"text/plain\",\n\t\"html\":                  \"text/html\",\n\t\"mpfd\":                  \"multipart/form-data\",\n\t\"x-www-form-urlencoded\": \"application/x-www-form-urlencoded\",\n\t\"json-api\":              \"application/vnd.api+json\",\n\t\"json-stream\":           \"application/x-json-stream\",\n\t\"octet-stream\":          \"application/octet-stream\",\n\t\"png\":                   \"image/png\",\n\t\"jpeg\":                  \"image/jpeg\",\n\t\"gif\":                   \"image/gif\",\n\t\"event-stream\":          \"text/event-stream\",\n}\n\nvar mimeTypePattern = regexp.MustCompile(\"^[^/]+/[^/]+$\")\nvar securityPairSepPattern = regexp.MustCompile(`\\|\\||&&`) // || for compatibility with old version, && for clarity\n\n// NewOperation creates a new Operation with default properties.\n// map[int]Response.\nfunc NewOperation(parser *Parser, options ...func(*Operation)) *Operation {\n\tif parser == nil {\n\t\tparser = New()\n\t}\n\n\tresult := &Operation{\n\t\tparser:           parser,\n\t\tRouterProperties: []RouteProperties{},\n\t\tOperation: spec.Operation{\n\t\t\tOperationProps: spec.OperationProps{\n\t\t\t\tID:           \"\",\n\t\t\t\tDescription:  \"\",\n\t\t\t\tSummary:      \"\",\n\t\t\t\tSecurity:     nil,\n\t\t\t\tExternalDocs: nil,\n\t\t\t\tDeprecated:   false,\n\t\t\t\tTags:         []string{},\n\t\t\t\tConsumes:     []string{},\n\t\t\t\tProduces:     []string{},\n\t\t\t\tSchemes:      []string{},\n\t\t\t\tParameters:   []spec.Parameter{},\n\t\t\t\tResponses: &spec.Responses{\n\t\t\t\t\tVendorExtensible: spec.VendorExtensible{\n\t\t\t\t\t\tExtensions: spec.Extensions{},\n\t\t\t\t\t},\n\t\t\t\t\tResponsesProps: spec.ResponsesProps{\n\t\t\t\t\t\tDefault:             nil,\n\t\t\t\t\t\tStatusCodeResponses: make(map[int]spec.Response),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tVendorExtensible: spec.VendorExtensible{\n\t\t\t\tExtensions: spec.Extensions{},\n\t\t\t},\n\t\t},\n\t\tcodeExampleFilesDir: \"\",\n\t}\n\n\tfor _, option := range options {\n\t\toption(result)\n\t}\n\n\treturn result\n}\n\n// SetCodeExampleFilesDirectory sets the directory to search for codeExamples.\nfunc SetCodeExampleFilesDirectory(directoryPath string) func(*Operation) {\n\treturn func(o *Operation) {\n\t\to.codeExampleFilesDir = directoryPath\n\t}\n}\n\n// ParseComment parses comment for given comment string and returns error if error occurs.\nfunc (operation *Operation) ParseComment(comment string, astFile *ast.File) error {\n\tcommentLine := strings.TrimSpace(strings.TrimLeft(comment, \"/\"))\n\tif len(commentLine) == 0 {\n\t\treturn nil\n\t}\n\n\tfields := FieldsByAnySpace(commentLine, 2)\n\tattribute := fields[0]\n\tlowerAttribute := strings.ToLower(attribute)\n\tvar lineRemainder string\n\tif len(fields) > 1 {\n\t\tlineRemainder = fields[1]\n\t}\n\tswitch lowerAttribute {\n\tcase stateAttr:\n\t\toperation.ParseStateComment(lineRemainder)\n\tcase descriptionAttr:\n\t\toperation.ParseDescriptionComment(lineRemainder)\n\tcase descriptionMarkdownAttr:\n\t\tcommentInfo, err := getMarkdownForTag(lineRemainder, operation.parser.markdownFileDir)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\toperation.ParseDescriptionComment(string(commentInfo))\n\tcase summaryAttr:\n\t\toperation.Summary = lineRemainder\n\tcase idAttr:\n\t\toperation.ID = lineRemainder\n\tcase tagsAttr:\n\t\toperation.ParseTagsComment(lineRemainder)\n\tcase acceptAttr:\n\t\treturn operation.ParseAcceptComment(lineRemainder)\n\tcase produceAttr:\n\t\treturn operation.ParseProduceComment(lineRemainder)\n\tcase paramAttr:\n\t\treturn operation.ParseParamComment(lineRemainder, astFile)\n\tcase successAttr, failureAttr, responseAttr:\n\t\treturn operation.ParseResponseComment(lineRemainder, astFile)\n\tcase headerAttr:\n\t\treturn operation.ParseResponseHeaderComment(lineRemainder, astFile)\n\tcase routerAttr:\n\t\treturn operation.ParseRouterComment(lineRemainder, false)\n\tcase deprecatedRouterAttr:\n\t\treturn operation.ParseRouterComment(lineRemainder, true)\n\tcase securityAttr:\n\t\treturn operation.ParseSecurityComment(lineRemainder)\n\tcase deprecatedAttr:\n\t\toperation.Deprecate()\n\tcase xCodeSamplesAttr:\n\t\treturn operation.ParseCodeSample(attribute, commentLine, lineRemainder)\n\tdefault:\n\t\treturn operation.ParseMetadata(attribute, lowerAttribute, lineRemainder)\n\t}\n\n\treturn nil\n}\n\n// ParseCodeSample parse code sample.\nfunc (operation *Operation) ParseCodeSample(attribute, _, lineRemainder string) error {\n\tif lineRemainder == \"file\" {\n\t\tdata, err := getCodeExampleForSummary(operation.Summary, operation.codeExampleFilesDir)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar valueJSON any\n\n\t\terr = json.Unmarshal(data, &valueJSON)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"annotation %s need a valid json value\", attribute)\n\t\t}\n\n\t\t// don't use the method provided by spec lib, because it will call toLower() on attribute names, which is wrongly\n\t\toperation.Extensions[attribute[1:]] = valueJSON\n\n\t\treturn nil\n\t}\n\n\t// Fallback into existing logic\n\treturn operation.ParseMetadata(attribute, strings.ToLower(attribute), lineRemainder)\n}\n\n// ParseStateComment parse state comment.\nfunc (operation *Operation) ParseStateComment(lineRemainder string) {\n\toperation.State = lineRemainder\n}\n\n// ParseDescriptionComment parse description comment.\nfunc (operation *Operation) ParseDescriptionComment(lineRemainder string) {\n\tif operation.Description == \"\" {\n\t\toperation.Description = lineRemainder\n\n\t\treturn\n\t}\n\n\toperation.Description = AppendDescription(operation.Description, lineRemainder)\n}\n\n// ParseMetadata parse metadata.\nfunc (operation *Operation) ParseMetadata(attribute, lowerAttribute, lineRemainder string) error {\n\t// parsing specific meta data extensions\n\tif strings.HasPrefix(lowerAttribute, \"@x-\") {\n\t\tif len(lineRemainder) == 0 {\n\t\t\treturn fmt.Errorf(\"annotation %s need a value\", attribute)\n\t\t}\n\n\t\tvar valueJSON any\n\n\t\terr := json.Unmarshal([]byte(lineRemainder), &valueJSON)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"annotation %s need a valid json value\", attribute)\n\t\t}\n\n\t\t// don't use the method provided by spec lib, because it will call toLower() on attribute names, which is wrongly\n\t\toperation.Extensions[attribute[1:]] = valueJSON\n\t}\n\n\treturn nil\n}\n\nvar paramPattern = regexp.MustCompile(`(\\S+)\\s+(\\w+)\\s+([\\S. ]+?)\\s+(\\w+)\\s+\"([^\"]+)\"`)\n\nfunc findInSlice(arr []string, target string) bool {\n\tfor _, str := range arr {\n\t\tif str == target {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// ParseParamComment parses params return []string of param properties\n// E.g. @Param\tqueryText\t\tformData\t      string\t  true\t\t        \"The email for login\"\n//\n//\t[param name]    [paramType] [data type]  [is mandatory?]   [Comment]\n//\n// E.g. @Param   some_id     path    int     true        \"Some ID\".\nfunc (operation *Operation) ParseParamComment(commentLine string, astFile *ast.File) error {\n\tmatches := paramPattern.FindStringSubmatch(commentLine)\n\tif len(matches) != 6 {\n\t\treturn fmt.Errorf(\"missing required param comment parameters \\\"%s\\\"\", commentLine)\n\t}\n\n\tname := matches[1]\n\tparamType := matches[2]\n\trefType, format := TransToValidSchemeTypeWithFormat(matches[3])\n\n\t// Detect refType\n\tobjectType := OBJECT\n\n\tif strings.HasPrefix(refType, \"[]\") {\n\t\tobjectType = ARRAY\n\t\trefType = strings.TrimPrefix(refType, \"[]\")\n\t\trefType, format = TransToValidSchemeTypeWithFormat(refType)\n\t} else if IsPrimitiveType(refType) ||\n\t\tparamType == \"formData\" && refType == \"file\" {\n\t\tobjectType = PRIMITIVE\n\t}\n\n\tvar enums []any\n\tif !IsPrimitiveType(refType) {\n\t\tschema, _ := operation.parser.getTypeSchema(refType, astFile, false)\n\t\tif schema != nil && len(schema.Type) == 1 && schema.Enum != nil {\n\t\t\tif objectType == OBJECT {\n\t\t\t\tobjectType = PRIMITIVE\n\t\t\t}\n\t\t\trefType, format = TransToValidSchemeTypeWithFormat(schema.Type[0])\n\t\t\tenums = schema.Enum\n\t\t}\n\t}\n\n\trequiredText := strings.ToLower(matches[4])\n\trequired := requiredText == \"true\" || requiredText == requiredLabel\n\tdescription := strings.Join(strings.Split(matches[5], \"\\\\n\"), \"\\n\")\n\n\tparam := createParameter(paramType, description, name, objectType, refType, format, required, enums, operation.parser.collectionFormatInQuery)\n\n\tswitch paramType {\n\tcase \"path\", \"header\", \"query\", \"formData\":\n\t\tswitch objectType {\n\t\tcase ARRAY:\n\t\t\tif !IsPrimitiveType(refType) && !(refType == \"file\" && paramType == \"formData\") {\n\t\t\t\treturn fmt.Errorf(\"%s is not supported array type for %s\", refType, paramType)\n\t\t\t}\n\t\tcase PRIMITIVE:\n\t\t\tbreak\n\t\tcase OBJECT:\n\t\t\tschema, err := operation.parser.getTypeSchema(refType, astFile, false)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif len(schema.Properties) == 0 {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\titems := schema.Properties.ToOrderedSchemaItems()\n\n\t\t\tfor _, item := range items {\n\t\t\t\tname, prop := item.Name, &item.Schema\n\t\t\t\tif len(prop.Type) == 0 {\n\t\t\t\t\tprop = operation.parser.getUnderlyingSchema(prop)\n\t\t\t\t\tif len(prop.Type) == 0 {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// load overridden type specific name from extensions if exists\n\t\t\t\t// query params check \"query\" extension first, then fall back to \"formData\"\n\t\t\t\tif paramType == \"query\" {\n\t\t\t\t\tif nameVal, ok := item.Schema.Extensions.GetString(queryTag); ok {\n\t\t\t\t\t\tname = nameVal\n\t\t\t\t\t\tif name == \"-\" {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if nameVal, ok := item.Schema.Extensions.GetString(\"formData\"); ok {\n\t\t\t\t\t\tname = nameVal\n\t\t\t\t\t\tif name == \"-\" {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if nameVal, ok := item.Schema.Extensions.GetString(paramType); ok {\n\t\t\t\t\tname = nameVal\n\t\t\t\t\tif name == \"-\" {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tswitch {\n\t\t\t\tcase prop.Type[0] == ARRAY:\n\t\t\t\t\tif prop.Items.Schema == nil {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\titemSchema := prop.Items.Schema\n\t\t\t\t\tif len(itemSchema.Type) == 0 {\n\t\t\t\t\t\titemSchema = operation.parser.getUnderlyingSchema(prop.Items.Schema)\n\t\t\t\t\t}\n\t\t\t\t\tif itemSchema == nil {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif len(itemSchema.Type) == 0 {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif !IsSimplePrimitiveType(itemSchema.Type[0]) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tcollectionFormat := operation.parser.collectionFormatInQuery\n\t\t\t\t\tif cfv, ok := prop.Extensions.GetString(collectionFormatTag); ok {\n\t\t\t\t\t\tcollectionFormat = cfv\n\t\t\t\t\t}\n\t\t\t\t\tparam = createParameter(paramType, prop.Description, name, prop.Type[0], itemSchema.Type[0], format, findInSlice(schema.Required, item.Name), itemSchema.Enum, collectionFormat)\n\n\t\t\t\tcase IsSimplePrimitiveType(prop.Type[0]):\n\t\t\t\t\tparam = createParameter(paramType, prop.Description, name, PRIMITIVE, prop.Type[0], format, findInSlice(schema.Required, item.Name), nil, operation.parser.collectionFormatInQuery)\n\t\t\t\tdefault:\n\t\t\t\t\toperation.parser.debug.Printf(\"skip field [%s] in %s is not supported type for %s\", name, refType, paramType)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tparam.Nullable = prop.Nullable\n\t\t\t\tparam.Format = prop.Format\n\t\t\t\tparam.Default = prop.Default\n\t\t\t\tparam.Example = prop.Example\n\t\t\t\tparam.Extensions = prop.Extensions\n\t\t\t\tparam.CommonValidations.Maximum = prop.Maximum\n\t\t\t\tparam.CommonValidations.Minimum = prop.Minimum\n\t\t\t\tparam.CommonValidations.ExclusiveMaximum = prop.ExclusiveMaximum\n\t\t\t\tparam.CommonValidations.ExclusiveMinimum = prop.ExclusiveMinimum\n\t\t\t\tparam.CommonValidations.MaxLength = prop.MaxLength\n\t\t\t\tparam.CommonValidations.MinLength = prop.MinLength\n\t\t\t\tparam.CommonValidations.Pattern = prop.Pattern\n\t\t\t\tparam.CommonValidations.MaxItems = prop.MaxItems\n\t\t\t\tparam.CommonValidations.MinItems = prop.MinItems\n\t\t\t\tparam.CommonValidations.UniqueItems = prop.UniqueItems\n\t\t\t\tparam.CommonValidations.MultipleOf = prop.MultipleOf\n\t\t\t\tparam.CommonValidations.Enum = prop.Enum\n\t\t\t\toperation.Operation.Parameters = append(operation.Operation.Parameters, param)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\tcase \"body\":\n\t\tif objectType == PRIMITIVE {\n\t\t\tparam.Schema = PrimitiveSchema(refType)\n\t\t} else {\n\t\t\tschema, err := operation.parseAPIObjectSchema(commentLine, objectType, refType, astFile)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tparam.Schema = schema\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"not supported paramType: %s\", paramType)\n\t}\n\n\terr := operation.parseParamAttribute(commentLine, objectType, refType, paramType, &param)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toperation.Operation.Parameters = append(operation.Operation.Parameters, param)\n\n\treturn nil\n}\n\nconst (\n\tformTag             = \"form\"\n\tjsonTag             = \"json\"\n\turiTag              = \"uri\"\n\theaderTag           = \"header\"\n\tqueryTag            = \"query\"\n\tparamTag            = \"param\"\n\tbindingTag          = \"binding\"\n\tdefaultTag          = \"default\"\n\tenumsTag            = \"enums\"\n\texampleTag          = \"example\"\n\tschemaExampleTag    = \"schemaExample\"\n\tformatTag           = \"format\"\n\ttitleTag            = \"title\"\n\tvalidateTag         = \"validate\"\n\tminimumTag          = \"minimum\"\n\tmaximumTag          = \"maximum\"\n\tminLengthTag        = \"minLength\"\n\tmaxLengthTag        = \"maxLength\"\n\tmultipleOfTag       = \"multipleOf\"\n\treadOnlyTag         = \"readonly\"\n\textensionsTag       = \"extensions\"\n\tcollectionFormatTag = \"collectionFormat\"\n)\n\nvar regexAttributes = map[string]*regexp.Regexp{\n\t// for Enums(A, B)\n\tenumsTag: regexp.MustCompile(`(?i)\\s+enums\\(.*?\\)(?:\\s|$)`),\n\t// for maximum(0)\n\tmaximumTag: regexp.MustCompile(`(?i)\\s+(?:maxinum|maximum)\\(.*?\\)(?:\\s|$)`),\n\t// for minimum(0)\n\tminimumTag: regexp.MustCompile(`(?i)\\s+(?:mininum|minimum)\\(.*?\\)(?:\\s|$)`),\n\t// for default(0)\n\tdefaultTag: regexp.MustCompile(`(?i)\\s+default\\(.*?\\)(?:\\s|$)`),\n\t// for minlength(0)\n\tminLengthTag: regexp.MustCompile(`(?i)\\s+minlength\\(.*?\\)(?:\\s|$)`),\n\t// for maxlength(0)\n\tmaxLengthTag: regexp.MustCompile(`(?i)\\s+maxlength\\(.*?\\)(?:\\s|$)`),\n\t// for format(email)\n\tformatTag: regexp.MustCompile(`(?i)\\s+format\\(.*?\\)(?:\\s|$)`),\n\t// for extensions(x-example=test)\n\textensionsTag: regexp.MustCompile(`(?i)\\s+extensions\\(.*?\\)(?:\\s|$)`),\n\t// for collectionFormat(csv)\n\tcollectionFormatTag: regexp.MustCompile(`(?i)\\s+collectionFormat\\(.*?\\)(?:\\s|$)`),\n\t// example(0)\n\texampleTag: regexp.MustCompile(`(?i)\\s+example\\(.*?\\)(?:\\s|$)`),\n\t// schemaExample(0)\n\tschemaExampleTag: regexp.MustCompile(`(?i)\\s+schemaExample\\(.*?\\)(?:\\s|$)`),\n}\n\nfunc (operation *Operation) parseParamAttribute(comment, objectType, schemaType, paramType string, param *spec.Parameter) error {\n\tschemaType = TransToValidSchemeType(schemaType)\n\n\tfor attrKey, re := range regexAttributes {\n\t\tattr, err := findAttr(re, comment)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch attrKey {\n\t\tcase enumsTag:\n\t\t\terr = setEnumParam(param, attr, objectType, schemaType, paramType)\n\t\tcase minimumTag, maximumTag:\n\t\t\terr = setNumberParam(param, attrKey, schemaType, attr, comment)\n\t\tcase defaultTag:\n\t\t\terr = setDefault(param, schemaType, attr)\n\t\tcase minLengthTag, maxLengthTag:\n\t\t\terr = setStringParam(param, attrKey, schemaType, attr, comment)\n\t\tcase formatTag:\n\t\t\tparam.Format = attr\n\t\tcase exampleTag:\n\t\t\terr = setExample(param, schemaType, attr)\n\t\tcase schemaExampleTag:\n\t\t\terr = setSchemaExample(param, schemaType, attr)\n\t\tcase extensionsTag:\n\t\t\tparam.Extensions = setExtensionParam(attr)\n\t\tcase collectionFormatTag:\n\t\t\terr = setCollectionFormatParam(param, attrKey, objectType, attr, comment)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc findAttr(re *regexp.Regexp, commentLine string) (string, error) {\n\tattr := re.FindString(commentLine)\n\n\tl, r := strings.Index(attr, \"(\"), strings.LastIndex(attr, \")\")\n\tif l == -1 || r == -1 {\n\t\treturn \"\", fmt.Errorf(\"can not find regex=%s, comment=%s\", re.String(), commentLine)\n\t}\n\n\treturn strings.TrimSpace(attr[l+1 : r]), nil\n}\n\nfunc setStringParam(param *spec.Parameter, name, schemaType, attr, commentLine string) error {\n\tif schemaType != STRING {\n\t\treturn fmt.Errorf(\"%s is attribute to set to a number. comment=%s got=%s\", name, commentLine, schemaType)\n\t}\n\n\tn, err := strconv.ParseInt(attr, 10, 64)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%s is allow only a number got=%s\", name, attr)\n\t}\n\n\tswitch name {\n\tcase minLengthTag:\n\t\tparam.MinLength = &n\n\tcase maxLengthTag:\n\t\tparam.MaxLength = &n\n\t}\n\n\treturn nil\n}\n\nfunc setNumberParam(param *spec.Parameter, name, schemaType, attr, commentLine string) error {\n\tswitch schemaType {\n\tcase INTEGER, NUMBER:\n\t\tn, err := strconv.ParseFloat(attr, 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"maximum is allow only a number. comment=%s got=%s\", commentLine, attr)\n\t\t}\n\n\t\tswitch name {\n\t\tcase minimumTag:\n\t\t\tparam.Minimum = &n\n\t\tcase maximumTag:\n\t\t\tparam.Maximum = &n\n\t\t}\n\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"%s is attribute to set to a number. comment=%s got=%s\", name, commentLine, schemaType)\n\t}\n}\n\nfunc setEnumParam(param *spec.Parameter, attr, objectType, schemaType, paramType string) error {\n\tfor _, e := range strings.Split(attr, \",\") {\n\t\te = strings.TrimSpace(e)\n\n\t\tvalue, err := defineType(schemaType, e)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tswitch objectType {\n\t\tcase ARRAY:\n\t\t\tparam.Items.Enum = append(param.Items.Enum, value)\n\t\tdefault:\n\t\t\tswitch paramType {\n\t\t\tcase \"body\":\n\t\t\t\tparam.Schema.Enum = append(param.Schema.Enum, value)\n\t\t\tdefault:\n\t\t\t\tparam.Enum = append(param.Enum, value)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc setExtensionParam(attr string) spec.Extensions {\n\textensions := spec.Extensions{}\n\n\tfor _, val := range splitNotWrapped(attr, ',') {\n\t\tparts := strings.SplitN(val, \"=\", 2)\n\t\tif len(parts) == 2 {\n\t\t\textensions.Add(parts[0], parts[1])\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(parts[0]) > 0 && string(parts[0][0]) == \"!\" {\n\t\t\textensions.Add(parts[0][1:], false)\n\n\t\t\tcontinue\n\t\t}\n\n\t\textensions.Add(parts[0], true)\n\t}\n\n\treturn extensions\n}\n\nfunc setCollectionFormatParam(param *spec.Parameter, name, schemaType, attr, commentLine string) error {\n\tif schemaType == ARRAY {\n\t\tparam.CollectionFormat = TransToValidCollectionFormat(attr)\n\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"%s is attribute to set to an array. comment=%s got=%s\", name, commentLine, schemaType)\n}\n\nfunc setDefault(param *spec.Parameter, schemaType string, value string) error {\n\tval, err := defineType(schemaType, value)\n\tif err != nil {\n\t\treturn nil // Don't set a default value if it's not valid\n\t}\n\n\tparam.Default = val\n\n\treturn nil\n}\n\nfunc setSchemaExample(param *spec.Parameter, schemaType string, value string) error {\n\tval, err := defineType(schemaType, value)\n\tif err != nil {\n\t\treturn nil // Don't set a example value if it's not valid\n\t}\n\t// skip schema\n\tif param.Schema == nil {\n\t\treturn nil\n\t}\n\n\tswitch v := val.(type) {\n\tcase string:\n\t\t//  replaces \\r \\n \\t in example string values.\n\t\tparam.Schema.Example = strings.NewReplacer(`\\r`, \"\\r\", `\\n`, \"\\n\", `\\t`, \"\\t\").Replace(v)\n\tdefault:\n\t\tparam.Schema.Example = val\n\t}\n\n\treturn nil\n}\n\nfunc setExample(param *spec.Parameter, schemaType string, value string) error {\n\tval, err := defineType(schemaType, value)\n\tif err != nil {\n\t\treturn nil // Don't set a example value if it's not valid\n\t}\n\n\tparam.Example = val\n\n\treturn nil\n}\n\n// defineType enum value define the type (object and array unsupported).\nfunc defineType(schemaType string, value string) (v any, err error) {\n\tschemaType = TransToValidSchemeType(schemaType)\n\n\tswitch schemaType {\n\tcase STRING:\n\t\treturn value, nil\n\tcase NUMBER:\n\t\tv, err = strconv.ParseFloat(value, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"enum value %s can't convert to %s err: %s\", value, schemaType, err)\n\t\t}\n\tcase INTEGER:\n\t\tv, err = strconv.Atoi(value)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"enum value %s can't convert to %s err: %s\", value, schemaType, err)\n\t\t}\n\tcase BOOLEAN:\n\t\tv, err = strconv.ParseBool(value)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"enum value %s can't convert to %s err: %s\", value, schemaType, err)\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"%s is unsupported type in enum value %s\", schemaType, value)\n\t}\n\n\treturn v, nil\n}\n\n// ParseTagsComment parses comment for given `tag` comment string.\nfunc (operation *Operation) ParseTagsComment(commentLine string) {\n\tfor _, tag := range strings.Split(commentLine, \",\") {\n\t\toperation.Tags = append(operation.Tags, strings.TrimSpace(tag))\n\t}\n}\n\n// ParseAcceptComment parses comment for given `accept` comment string.\nfunc (operation *Operation) ParseAcceptComment(commentLine string) error {\n\treturn parseMimeTypeList(commentLine, &operation.Consumes, \"%v accept type can't be accepted\")\n}\n\n// ParseProduceComment parses comment for given `produce` comment string.\nfunc (operation *Operation) ParseProduceComment(commentLine string) error {\n\treturn parseMimeTypeList(commentLine, &operation.Produces, \"%v produce type can't be accepted\")\n}\n\n// parseMimeTypeList parses a list of MIME Types for a comment like\n// `produce` (`Content-Type:` response header) or\n// `accept` (`Accept:` request header).\nfunc parseMimeTypeList(mimeTypeList string, typeList *[]string, format string) error {\n\tfor _, typeName := range strings.Split(mimeTypeList, \",\") {\n\t\tif mimeTypePattern.MatchString(typeName) {\n\t\t\t*typeList = append(*typeList, typeName)\n\n\t\t\tcontinue\n\t\t}\n\n\t\taliasMimeType, ok := mimeTypeAliases[typeName]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(format, typeName)\n\t\t}\n\n\t\t*typeList = append(*typeList, aliasMimeType)\n\t}\n\n\treturn nil\n}\n\nvar routerPattern = regexp.MustCompile(`^(/[\\w./\\-{}\\(\\)+:$~@]*)[[:blank:]]+\\[(\\w+)]`)\n\n// ParseRouterComment parses comment for given `router` comment string.\nfunc (operation *Operation) ParseRouterComment(commentLine string, deprecated bool) error {\n\tmatches := routerPattern.FindStringSubmatch(commentLine)\n\tif len(matches) != 3 {\n\t\treturn fmt.Errorf(\"can not parse router comment \\\"%s\\\"\", commentLine)\n\t}\n\n\tsignature := RouteProperties{\n\t\tPath:       matches[1],\n\t\tHTTPMethod: strings.ToUpper(matches[2]),\n\t\tDeprecated: deprecated,\n\t}\n\n\tif _, ok := allMethod[signature.HTTPMethod]; !ok {\n\t\treturn fmt.Errorf(\"invalid method: %s\", signature.HTTPMethod)\n\t}\n\n\toperation.RouterProperties = append(operation.RouterProperties, signature)\n\n\treturn nil\n}\n\n// ParseSecurityComment parses comment for given `security` comment string.\nfunc (operation *Operation) ParseSecurityComment(commentLine string) error {\n\tif len(commentLine) == 0 {\n\t\toperation.Security = []map[string][]string{}\n\t\treturn nil\n\t}\n\n\tvar (\n\t\tsecurityMap    = make(map[string][]string)\n\t\tsecuritySource = commentLine[strings.Index(commentLine, \"@Security\")+1:]\n\t)\n\n\tfor _, securityOption := range securityPairSepPattern.Split(securitySource, -1) {\n\t\tsecurityOption = strings.TrimSpace(securityOption)\n\n\t\tleft, right := strings.Index(securityOption, \"[\"), strings.Index(securityOption, \"]\")\n\n\t\tif !(left == -1 && right == -1) {\n\t\t\tscopes := securityOption[left+1 : right]\n\n\t\t\tvar options []string\n\n\t\t\tfor _, scope := range strings.Split(scopes, \",\") {\n\t\t\t\toptions = append(options, strings.TrimSpace(scope))\n\t\t\t}\n\n\t\t\tsecurityKey := securityOption[0:left]\n\t\t\tsecurityMap[securityKey] = append(securityMap[securityKey], options...)\n\t\t} else {\n\t\t\tsecurityKey := strings.TrimSpace(securityOption)\n\t\t\tsecurityMap[securityKey] = []string{}\n\t\t}\n\t}\n\n\toperation.Security = append(operation.Security, securityMap)\n\n\treturn nil\n}\n\n// findTypeDef attempts to find the *ast.TypeSpec for a specific type given the\n// type's name and the package's import path.\n// TODO: improve finding external pkg.\nfunc findTypeDef(importPath, typeName string) (*ast.TypeSpec, error) {\n\tcwd, err := os.Getwd()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconf := loader.Config{\n\t\tParserMode: goparser.SpuriousErrors,\n\t\tCwd:        cwd,\n\t}\n\n\tconf.Import(importPath)\n\n\tlprog, err := conf.Load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// If the pkg is vendored, the actual pkg path is going to resemble\n\t// something like \"{importPath}/vendor/{importPath}\"\n\tfor k := range lprog.AllPackages {\n\t\trealPkgPath := k.Path()\n\n\t\tif strings.Contains(realPkgPath, \"vendor/\"+importPath) {\n\t\t\timportPath = realPkgPath\n\t\t}\n\t}\n\n\tpkgInfo := lprog.Package(importPath)\n\n\tif pkgInfo == nil {\n\t\treturn nil, fmt.Errorf(\"package was nil\")\n\t}\n\n\t// TODO: possibly cache pkgInfo since it's an expensive operation\n\tfor i := range pkgInfo.Files {\n\t\tfor _, astDeclaration := range pkgInfo.Files[i].Decls {\n\t\t\tgeneralDeclaration, ok := astDeclaration.(*ast.GenDecl)\n\t\t\tif ok && generalDeclaration.Tok == token.TYPE {\n\t\t\t\tfor _, astSpec := range generalDeclaration.Specs {\n\t\t\t\t\ttypeSpec, ok := astSpec.(*ast.TypeSpec)\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tif typeSpec.Name.String() == typeName {\n\t\t\t\t\t\t\treturn typeSpec, nil\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"type spec not found\")\n}\n\nvar responsePattern = regexp.MustCompile(`^([\\w,]+)\\s+([\\w{}]+)\\s+([\\w\\-.\\\\{}=,\\[\\s\\]]+)\\s*(\".*)?`)\n\n// ResponseType{data1=Type1,data2=Type2}.\nvar combinedPattern = regexp.MustCompile(`^([\\w\\-./\\[\\]]+){(.*)}$`)\n\nfunc (operation *Operation) parseObjectSchema(refType string, astFile *ast.File) (*spec.Schema, error) {\n\treturn parseObjectSchema(operation.parser, refType, astFile)\n}\n\nfunc parseObjectSchema(parser *Parser, refType string, astFile *ast.File) (*spec.Schema, error) {\n\tswitch {\n\tcase refType == NIL:\n\t\treturn nil, nil\n\tcase refType == INTERFACE:\n\t\treturn &spec.Schema{}, nil\n\tcase refType == ANY:\n\t\treturn &spec.Schema{}, nil\n\tcase IsGolangPrimitiveType(refType):\n\t\treturn TransToValidPrimitiveSchema(refType), nil\n\tcase IsPrimitiveType(refType):\n\t\treturn PrimitiveSchema(refType), nil\n\tcase strings.HasPrefix(refType, \"[]\"):\n\t\tschema, err := parseObjectSchema(parser, refType[2:], astFile)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn spec.ArrayProperty(schema), nil\n\tcase strings.HasPrefix(refType, \"map[\"):\n\t\t// ignore key type\n\t\tidx := strings.Index(refType, \"]\")\n\t\tif idx < 0 {\n\t\t\treturn nil, fmt.Errorf(\"invalid type: %s\", refType)\n\t\t}\n\n\t\trefType = refType[idx+1:]\n\t\tif refType == INTERFACE || refType == ANY {\n\t\t\treturn spec.MapProperty(nil), nil\n\t\t}\n\n\t\tschema, err := parseObjectSchema(parser, refType, astFile)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn spec.MapProperty(schema), nil\n\tcase strings.Contains(refType, \"{\"):\n\t\treturn parseCombinedObjectSchema(parser, refType, astFile)\n\tdefault:\n\t\tif parser != nil { // checking refType has existing in 'TypeDefinitions'\n\t\t\tschema, err := parser.getTypeSchema(refType, astFile, true)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturn schema, nil\n\t\t}\n\n\t\treturn RefSchema(refType), nil\n\t}\n}\n\nfunc parseFields(s string) []string {\n\tnestLevel := 0\n\n\treturn strings.FieldsFunc(s, func(char rune) bool {\n\t\tif char == '{' {\n\t\t\tnestLevel++\n\n\t\t\treturn false\n\t\t} else if char == '}' {\n\t\t\tnestLevel--\n\n\t\t\treturn false\n\t\t}\n\n\t\treturn char == ',' && nestLevel == 0\n\t})\n}\n\nfunc parseCombinedObjectSchema(parser *Parser, refType string, astFile *ast.File) (*spec.Schema, error) {\n\tmatches := combinedPattern.FindStringSubmatch(refType)\n\tif len(matches) != 3 {\n\t\treturn nil, fmt.Errorf(\"invalid type: %s\", refType)\n\t}\n\n\tschema, err := parseObjectSchema(parser, matches[1], astFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfields, props := parseFields(matches[2]), map[string]spec.Schema{}\n\n\tfor _, field := range fields {\n\t\tkeyVal := strings.SplitN(field, \"=\", 2)\n\t\tif len(keyVal) == 2 {\n\t\t\tschema, err := parseObjectSchema(parser, keyVal[1], astFile)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif schema == nil {\n\t\t\t\tschema = PrimitiveSchema(OBJECT)\n\t\t\t}\n\n\t\t\tprops[keyVal[0]] = *schema\n\t\t}\n\t}\n\n\tif len(props) == 0 {\n\t\treturn schema, nil\n\t}\n\n\tif schema.Ref.GetURL() == nil && len(schema.Type) > 0 && schema.Type[0] == OBJECT && len(schema.Properties) == 0 && schema.AdditionalProperties == nil {\n\t\tschema.Properties = props\n\t\treturn schema, nil\n\t}\n\n\treturn spec.ComposedSchema(*schema, spec.Schema{\n\t\tSchemaProps: spec.SchemaProps{\n\t\t\tType:       []string{OBJECT},\n\t\t\tProperties: props,\n\t\t},\n\t}), nil\n}\n\nfunc (operation *Operation) parseAPIObjectSchema(commentLine, schemaType, refType string, astFile *ast.File) (*spec.Schema, error) {\n\tif strings.HasSuffix(refType, \",\") && strings.Contains(refType, \"[\") {\n\t\t// regexp may have broken generic syntax. find closing bracket and add it back\n\t\tallMatchesLenOffset := strings.Index(commentLine, refType) + len(refType)\n\t\tlostPartEndIdx := strings.Index(commentLine[allMatchesLenOffset:], \"]\")\n\t\tif lostPartEndIdx >= 0 {\n\t\t\trefType += commentLine[allMatchesLenOffset : allMatchesLenOffset+lostPartEndIdx+1]\n\t\t}\n\t}\n\n\tswitch schemaType {\n\tcase OBJECT:\n\t\tif !strings.HasPrefix(refType, \"[]\") {\n\t\t\treturn operation.parseObjectSchema(refType, astFile)\n\t\t}\n\n\t\trefType = refType[2:]\n\n\t\tfallthrough\n\tcase ARRAY:\n\t\tschema, err := operation.parseObjectSchema(refType, astFile)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn spec.ArrayProperty(schema), nil\n\tdefault:\n\t\treturn PrimitiveSchema(schemaType), nil\n\t}\n}\n\n// ParseResponseComment parses comment for given `response` comment string.\nfunc (operation *Operation) ParseResponseComment(commentLine string, astFile *ast.File) error {\n\tmatches := responsePattern.FindStringSubmatch(commentLine)\n\tif len(matches) != 5 {\n\t\terr := operation.ParseEmptyResponseComment(commentLine)\n\t\tif err != nil {\n\t\t\treturn operation.ParseEmptyResponseOnly(commentLine)\n\t\t}\n\n\t\treturn err\n\t}\n\n\tdescription := strings.Trim(matches[4], \"\\\"\")\n\n\tschema, err := operation.parseAPIObjectSchema(commentLine, strings.Trim(matches[2], \"{}\"), strings.TrimSpace(matches[3]), astFile)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, codeStr := range strings.Split(matches[1], \",\") {\n\t\tif strings.EqualFold(codeStr, defaultTag) {\n\t\t\toperation.DefaultResponse().WithSchema(schema).WithDescription(description)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tcode, err := strconv.Atoi(codeStr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"can not parse response comment \\\"%s\\\"\", commentLine)\n\t\t}\n\n\t\tresp := spec.NewResponse().WithSchema(schema).WithDescription(description)\n\t\tif description == \"\" {\n\t\t\tresp.WithDescription(http.StatusText(code))\n\t\t}\n\n\t\toperation.AddResponse(code, resp)\n\t}\n\n\treturn nil\n}\n\nfunc newHeaderSpec(schemaType, description string) spec.Header {\n\treturn spec.Header{\n\t\tSimpleSchema: spec.SimpleSchema{\n\t\t\tType: schemaType,\n\t\t},\n\t\tHeaderProps: spec.HeaderProps{\n\t\t\tDescription: description,\n\t\t},\n\t\tVendorExtensible: spec.VendorExtensible{\n\t\t\tExtensions: nil,\n\t\t},\n\t\tCommonValidations: spec.CommonValidations{\n\t\t\tMaximum:          nil,\n\t\t\tExclusiveMaximum: false,\n\t\t\tMinimum:          nil,\n\t\t\tExclusiveMinimum: false,\n\t\t\tMaxLength:        nil,\n\t\t\tMinLength:        nil,\n\t\t\tPattern:          \"\",\n\t\t\tMaxItems:         nil,\n\t\t\tMinItems:         nil,\n\t\t\tUniqueItems:      false,\n\t\t\tMultipleOf:       nil,\n\t\t\tEnum:             nil,\n\t\t},\n\t}\n}\n\n// ParseResponseHeaderComment parses comment for given `response header` comment string.\nfunc (operation *Operation) ParseResponseHeaderComment(commentLine string, _ *ast.File) error {\n\tmatches := responsePattern.FindStringSubmatch(commentLine)\n\tif len(matches) != 5 {\n\t\treturn fmt.Errorf(\"can not parse response comment \\\"%s\\\"\", commentLine)\n\t}\n\n\theader := newHeaderSpec(strings.Trim(matches[2], \"{}\"), strings.Trim(matches[4], \"\\\"\"))\n\n\theaderKey := strings.TrimSpace(matches[3])\n\n\tif strings.EqualFold(matches[1], \"all\") {\n\t\tif operation.Responses.Default != nil {\n\t\t\toperation.Responses.Default.Headers[headerKey] = header\n\t\t}\n\n\t\tif operation.Responses.StatusCodeResponses != nil {\n\t\t\tfor code, response := range operation.Responses.StatusCodeResponses {\n\t\t\t\tresponse.Headers[headerKey] = header\n\t\t\t\toperation.Responses.StatusCodeResponses[code] = response\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tfor _, codeStr := range strings.Split(matches[1], \",\") {\n\t\tif strings.EqualFold(codeStr, defaultTag) {\n\t\t\tif operation.Responses.Default != nil {\n\t\t\t\toperation.Responses.Default.Headers[headerKey] = header\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tcode, err := strconv.Atoi(codeStr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"can not parse response comment \\\"%s\\\"\", commentLine)\n\t\t}\n\n\t\tif operation.Responses.StatusCodeResponses != nil {\n\t\t\tresponse, responseExist := operation.Responses.StatusCodeResponses[code]\n\t\t\tif responseExist {\n\t\t\t\tresponse.Headers[headerKey] = header\n\n\t\t\t\toperation.Responses.StatusCodeResponses[code] = response\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nvar emptyResponsePattern = regexp.MustCompile(`([\\w,]+)\\s+\"(.*)\"`)\n\n// ParseEmptyResponseComment parse only comment out status code and description,eg: @Success 200 \"it's ok\".\nfunc (operation *Operation) ParseEmptyResponseComment(commentLine string) error {\n\tmatches := emptyResponsePattern.FindStringSubmatch(commentLine)\n\tif len(matches) != 3 {\n\t\treturn fmt.Errorf(\"can not parse response comment \\\"%s\\\"\", commentLine)\n\t}\n\n\tdescription := strings.Trim(matches[2], \"\\\"\")\n\n\tfor _, codeStr := range strings.Split(matches[1], \",\") {\n\t\tif strings.EqualFold(codeStr, defaultTag) {\n\t\t\toperation.DefaultResponse().WithDescription(description)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tcode, err := strconv.Atoi(codeStr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"can not parse response comment \\\"%s\\\"\", commentLine)\n\t\t}\n\n\t\toperation.AddResponse(code, spec.NewResponse().WithDescription(description))\n\t}\n\n\treturn nil\n}\n\n// ParseEmptyResponseOnly parse only comment out status code ,eg: @Success 200.\nfunc (operation *Operation) ParseEmptyResponseOnly(commentLine string) error {\n\tfor _, codeStr := range strings.Split(commentLine, \",\") {\n\t\tif strings.EqualFold(codeStr, defaultTag) {\n\t\t\t_ = operation.DefaultResponse()\n\n\t\t\tcontinue\n\t\t}\n\n\t\tcode, err := strconv.Atoi(codeStr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"can not parse response comment \\\"%s\\\"\", commentLine)\n\t\t}\n\n\t\toperation.AddResponse(code, spec.NewResponse().WithDescription(http.StatusText(code)))\n\t}\n\n\treturn nil\n}\n\n// DefaultResponse return the default response member pointer.\nfunc (operation *Operation) DefaultResponse() *spec.Response {\n\tif operation.Responses.Default == nil {\n\t\toperation.Responses.Default = &spec.Response{\n\t\t\tResponseProps: spec.ResponseProps{\n\t\t\t\tDescription: \"\",\n\t\t\t\tHeaders:     make(map[string]spec.Header),\n\t\t\t},\n\t\t}\n\t}\n\n\treturn operation.Responses.Default\n}\n\n// AddResponse add a response for a code.\nfunc (operation *Operation) AddResponse(code int, response *spec.Response) {\n\tif response.Headers == nil {\n\t\tresponse.Headers = make(map[string]spec.Header)\n\t}\n\n\toperation.Responses.StatusCodeResponses[code] = *response\n}\n\n// createParameter returns swagger spec.Parameter for given  paramType, description, paramName, schemaType, required.\nfunc createParameter(paramType, description, paramName, objectType, schemaType string, format string, required bool, enums []any, collectionFormat string) spec.Parameter {\n\t// //five possible parameter types. \tquery, path, body, header, form\n\tresult := spec.Parameter{\n\t\tParamProps: spec.ParamProps{\n\t\t\tName:        paramName,\n\t\t\tDescription: description,\n\t\t\tRequired:    required,\n\t\t\tIn:          paramType,\n\t\t},\n\t}\n\n\tif paramType == \"body\" {\n\t\treturn result\n\t}\n\n\tswitch objectType {\n\tcase ARRAY:\n\t\tresult.Type = objectType\n\t\tresult.CollectionFormat = collectionFormat\n\t\tresult.Items = &spec.Items{\n\t\t\tCommonValidations: spec.CommonValidations{\n\t\t\t\tEnum: enums,\n\t\t\t},\n\t\t\tSimpleSchema: spec.SimpleSchema{\n\t\t\t\tType:   schemaType,\n\t\t\t\tFormat: format,\n\t\t\t},\n\t\t}\n\tcase PRIMITIVE, OBJECT:\n\t\tresult.Type = schemaType\n\t\tresult.Enum = enums\n\t\tresult.Format = format\n\t}\n\treturn result\n}\n\nfunc getCodeExampleForSummary(summaryName string, dirPath string) ([]byte, error) {\n\tdirEntries, err := os.ReadDir(dirPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, entry := range dirEntries {\n\t\tif entry.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tfileName := entry.Name()\n\n\t\tif !strings.Contains(fileName, \".json\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.Contains(fileName, summaryName) {\n\t\t\tfullPath := filepath.Join(dirPath, fileName)\n\n\t\t\tcommentInfo, err := os.ReadFile(fullPath)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"Failed to read code example file %s error: %s \", fullPath, err)\n\t\t\t}\n\n\t\t\treturn commentInfo, nil\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"unable to find code example file for tag %s in the given directory\", summaryName)\n}\n"
  },
  {
    "path": "operation_test.go",
    "content": "package swag\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"go/ast\"\n\tgoparser \"go/parser\"\n\t\"go/token\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/go-openapi/spec\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestParseEmptyComment(t *testing.T) {\n\tt.Parallel()\n\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(\"//\", nil)\n\n\tassert.NoError(t, err)\n}\n\nfunc TestParseTagsComment(t *testing.T) {\n\tt.Parallel()\n\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(`/@Tags pet, store,user`, nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, operation.Tags, []string{\"pet\", \"store\", \"user\"})\n}\n\nfunc TestParseAcceptComment(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Accept json,xml,plain,html,mpfd,x-www-form-urlencoded,json-api,json-stream,octet-stream,png,jpeg,gif,application/xhtml+xml,application/health+json`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t,\n\t\toperation.Consumes,\n\t\t[]string{\"application/json\",\n\t\t\t\"text/xml\",\n\t\t\t\"text/plain\",\n\t\t\t\"text/html\",\n\t\t\t\"multipart/form-data\",\n\t\t\t\"application/x-www-form-urlencoded\",\n\t\t\t\"application/vnd.api+json\",\n\t\t\t\"application/x-json-stream\",\n\t\t\t\"application/octet-stream\",\n\t\t\t\"image/png\",\n\t\t\t\"image/jpeg\",\n\t\t\t\"image/gif\",\n\t\t\t\"application/xhtml+xml\",\n\t\t\t\"application/health+json\"})\n}\n\nfunc TestParseAcceptCommentErr(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Accept unknown`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.Error(t, err)\n}\n\nfunc TestParseProduceComment(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\n    \"produces\": [\n        \"application/json\",\n        \"text/xml\",\n        \"text/plain\",\n        \"text/html\",\n        \"multipart/form-data\",\n        \"application/x-www-form-urlencoded\",\n        \"application/vnd.api+json\",\n        \"application/x-json-stream\",\n\t\t\"application/octet-stream\",\n\t\t\"image/png\",\n\t\t\"image/jpeg\",\n\t\t\"image/gif\",\n\t\t\"application/health+json\"\n    ]\n}`\n\tcomment := `/@Produce json,xml,plain,html,mpfd,x-www-form-urlencoded,json-api,json-stream,octet-stream,png,jpeg,gif,application/health+json`\n\toperation := new(Operation)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\tassert.JSONEq(t, expected, string(b))\n}\n\nfunc TestParseProduceCommentErr(t *testing.T) {\n\tt.Parallel()\n\n\toperation := new(Operation)\n\terr := operation.ParseComment(\"/@Produce foo\", nil)\n\tassert.Error(t, err)\n}\n\nfunc TestParseRouterComment(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Router /customer/get-wishlist/{wishlist_id} [get]`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\tassert.Len(t, operation.RouterProperties, 1)\n\tassert.Equal(t, \"/customer/get-wishlist/{wishlist_id}\", operation.RouterProperties[0].Path)\n\tassert.Equal(t, \"GET\", operation.RouterProperties[0].HTTPMethod)\n\n\tcomment = `/@Router /customer/get-wishlist/{wishlist_id} [unknown]`\n\toperation = NewOperation(nil)\n\terr = operation.ParseComment(comment, nil)\n\tassert.Error(t, err)\n}\n\nfunc TestParseRouterMultipleComments(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Router /customer/get-wishlist/{wishlist_id} [get]`\n\tanotherComment := `/@Router /customer/get-the-wishlist/{wishlist_id} [post]`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\terr = operation.ParseComment(anotherComment, nil)\n\tassert.NoError(t, err)\n\n\tassert.Len(t, operation.RouterProperties, 2)\n\tassert.Equal(t, \"/customer/get-wishlist/{wishlist_id}\", operation.RouterProperties[0].Path)\n\tassert.Equal(t, \"GET\", operation.RouterProperties[0].HTTPMethod)\n\tassert.Equal(t, \"/customer/get-the-wishlist/{wishlist_id}\", operation.RouterProperties[1].Path)\n\tassert.Equal(t, \"POST\", operation.RouterProperties[1].HTTPMethod)\n}\n\nfunc TestParseRouterOnlySlash(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `// @Router / [get]`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\tassert.Len(t, operation.RouterProperties, 1)\n\tassert.Equal(t, \"/\", operation.RouterProperties[0].Path)\n\tassert.Equal(t, \"GET\", operation.RouterProperties[0].HTTPMethod)\n}\n\nfunc TestParseRouterCommentWithPlusSign(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Router /customer/get-wishlist/{proxy+} [post]`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\tassert.Len(t, operation.RouterProperties, 1)\n\tassert.Equal(t, \"/customer/get-wishlist/{proxy+}\", operation.RouterProperties[0].Path)\n\tassert.Equal(t, \"POST\", operation.RouterProperties[0].HTTPMethod)\n}\n\nfunc TestParseRouterCommentWithDollarSign(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Router /customer/get-wishlist/{wishlist_id}$move [post]`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\tassert.Len(t, operation.RouterProperties, 1)\n\tassert.Equal(t, \"/customer/get-wishlist/{wishlist_id}$move\", operation.RouterProperties[0].Path)\n\tassert.Equal(t, \"POST\", operation.RouterProperties[0].HTTPMethod)\n}\n\nfunc TestParseRouterCommentWithParens(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Router /customer({id}) [get]`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\tassert.Len(t, operation.RouterProperties, 1)\n\tassert.Equal(t, \"/customer({id})\", operation.RouterProperties[0].Path)\n\tassert.Equal(t, \"GET\", operation.RouterProperties[0].HTTPMethod)\n}\n\nfunc TestParseRouterCommentNoDollarSignAtPathStartErr(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Router $customer/get-wishlist/{wishlist_id}$move [post]`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.Error(t, err)\n}\n\nfunc TestParseRouterCommentWithColonSign(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Router /customer/get-wishlist/{wishlist_id}:move [post]`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\tassert.Len(t, operation.RouterProperties, 1)\n\tassert.Equal(t, \"/customer/get-wishlist/{wishlist_id}:move\", operation.RouterProperties[0].Path)\n\tassert.Equal(t, \"POST\", operation.RouterProperties[0].HTTPMethod)\n}\n\nfunc TestParseRouterCommentNoColonSignAtPathStartErr(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Router :customer/get-wishlist/{wishlist_id}:move [post]`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.Error(t, err)\n}\n\nfunc TestParseRouterCommentWithTilde(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Router /customer/{id}/~last-name [patch]`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n}\n\nfunc TestParseRouterCommentWithAt(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Router /users/@{id} [get]`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n}\n\nfunc TestParseRouterCommentMethodSeparationErr(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Router /api/{id}|,*[get`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.Error(t, err)\n}\n\nfunc TestParseRouterCommentMethodMissingErr(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `/@Router /customer/get-wishlist/{wishlist_id}`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.Error(t, err)\n}\n\nfunc TestOperation_ParseResponseWithDefault(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success default {object} nil \"An empty response\"`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"An empty response\", operation.Responses.Default.Description)\n\n\tcomment = `@Success 200,default {string} Response \"A response\"`\n\toperation = NewOperation(nil)\n\n\terr = operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"A response\", operation.Responses.Default.Description)\n\tassert.Equal(t, \"A response\", operation.Responses.StatusCodeResponses[200].Description)\n}\n\nfunc TestParseResponseSuccessCommentWithEmptyResponse(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {object} nil \"An empty response\"`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tresponse := operation.Responses.StatusCodeResponses[200]\n\tassert.Equal(t, `An empty response`, response.Description)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"An empty response\"\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseFailureCommentWithEmptyResponse(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Failure 500 {object} nil`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\texpected := `{\n    \"responses\": {\n        \"500\": {\n            \"description\": \"Internal Server Error\"\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithObjectType(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {object} model.OrderRow \"Error message, if code != 200`\n\toperation := NewOperation(nil)\n\toperation.parser.addTestType(\"model.OrderRow\")\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tresponse := operation.Responses.StatusCodeResponses[200]\n\tassert.Equal(t, `Error message, if code != 200`, response.Description)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"Error message, if code != 200\",\n            \"schema\": {\n                \"$ref\": \"#/definitions/model.OrderRow\"\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithNestedPrimitiveType(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {object} model.CommonHeader{data=string,data2=int} \"Error message, if code != 200`\n\toperation := NewOperation(nil)\n\n\toperation.parser.addTestType(\"model.CommonHeader\")\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tresponse := operation.Responses.StatusCodeResponses[200]\n\tassert.Equal(t, `Error message, if code != 200`, response.Description)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"Error message, if code != 200\",\n            \"schema\": {\n                \"allOf\": [\n                    {\n                        \"$ref\": \"#/definitions/model.CommonHeader\"\n                    },\n                    {\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"data\": {\n                                \"type\": \"string\"\n                            },\n                            \"data2\": {\n                                \"type\": \"integer\"\n                            }\n                        }\n                    }\n                ]\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithNestedPrimitiveArrayType(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {object} model.CommonHeader{data=[]string,data2=[]int} \"Error message, if code != 200`\n\toperation := NewOperation(nil)\n\n\toperation.parser.addTestType(\"model.CommonHeader\")\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tresponse := operation.Responses.StatusCodeResponses[200]\n\tassert.Equal(t, `Error message, if code != 200`, response.Description)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"Error message, if code != 200\",\n            \"schema\": {\n                \"allOf\": [\n                    {\n                        \"$ref\": \"#/definitions/model.CommonHeader\"\n                    },\n                    {\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"data\": {\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"type\": \"string\"\n                                }\n                            },\n                            \"data2\": {\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"type\": \"integer\"\n                                }\n                            }\n                        }\n                    }\n                ]\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithNestedObjectType(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {object} model.CommonHeader{data=model.Payload,data2=model.Payload2} \"Error message, if code != 200`\n\toperation := NewOperation(nil)\n\toperation.parser.addTestType(\"model.CommonHeader\")\n\toperation.parser.addTestType(\"model.Payload\")\n\toperation.parser.addTestType(\"model.Payload2\")\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tresponse := operation.Responses.StatusCodeResponses[200]\n\tassert.Equal(t, `Error message, if code != 200`, response.Description)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"Error message, if code != 200\",\n            \"schema\": {\n                \"allOf\": [\n                    {\n                        \"$ref\": \"#/definitions/model.CommonHeader\"\n                    },\n                    {\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"data\": {\n                                \"$ref\": \"#/definitions/model.Payload\"\n                            },\n                            \"data2\": {\n                                \"$ref\": \"#/definitions/model.Payload2\"\n                            }\n                        }\n                    }\n                ]\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithNestedArrayObjectType(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {object} model.CommonHeader{data=[]model.Payload,data2=[]model.Payload2} \"Error message, if code != 200`\n\toperation := NewOperation(nil)\n\n\toperation.parser.addTestType(\"model.CommonHeader\")\n\toperation.parser.addTestType(\"model.Payload\")\n\toperation.parser.addTestType(\"model.Payload2\")\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tresponse := operation.Responses.StatusCodeResponses[200]\n\tassert.Equal(t, `Error message, if code != 200`, response.Description)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"Error message, if code != 200\",\n            \"schema\": {\n                \"allOf\": [\n                    {\n                        \"$ref\": \"#/definitions/model.CommonHeader\"\n                    },\n                    {\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"data\": {\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/definitions/model.Payload\"\n                                }\n                            },\n                            \"data2\": {\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/definitions/model.Payload2\"\n                                }\n                            }\n                        }\n                    }\n                ]\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithNestedFields(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {object} model.CommonHeader{data1=int,data2=[]int,data3=model.Payload,data4=[]model.Payload} \"Error message, if code != 200`\n\toperation := NewOperation(nil)\n\n\toperation.parser.addTestType(\"model.CommonHeader\")\n\toperation.parser.addTestType(\"model.Payload\")\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tresponse := operation.Responses.StatusCodeResponses[200]\n\tassert.Equal(t, `Error message, if code != 200`, response.Description)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"Error message, if code != 200\",\n            \"schema\": {\n                \"allOf\": [\n                    {\n                        \"$ref\": \"#/definitions/model.CommonHeader\"\n                    },\n                    {\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"data1\": {\n                                \"type\": \"integer\"\n                            },\n                            \"data2\": {\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"type\": \"integer\"\n                                }\n                            },\n                            \"data3\": {\n                                \"$ref\": \"#/definitions/model.Payload\"\n                            },\n                            \"data4\": {\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/definitions/model.Payload\"\n                                }\n                            }\n                        }\n                    }\n                ]\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithDeepNestedFields(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {object} model.CommonHeader{data1=int,data2=[]int,data3=model.Payload{data1=int,data2=model.DeepPayload},data4=[]model.Payload{data1=[]int,data2=[]model.DeepPayload}} \"Error message, if code != 200`\n\toperation := NewOperation(nil)\n\n\toperation.parser.addTestType(\"model.CommonHeader\")\n\toperation.parser.addTestType(\"model.Payload\")\n\toperation.parser.addTestType(\"model.DeepPayload\")\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tresponse := operation.Responses.StatusCodeResponses[200]\n\tassert.Equal(t, `Error message, if code != 200`, response.Description)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"Error message, if code != 200\",\n            \"schema\": {\n                \"allOf\": [\n                    {\n                        \"$ref\": \"#/definitions/model.CommonHeader\"\n                    },\n                    {\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"data1\": {\n                                \"type\": \"integer\"\n                            },\n                            \"data2\": {\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"type\": \"integer\"\n                                }\n                            },\n                            \"data3\": {\n                                \"allOf\": [\n                                    {\n                                        \"$ref\": \"#/definitions/model.Payload\"\n                                    },\n                                    {\n                                        \"type\": \"object\",\n                                        \"properties\": {\n                                            \"data1\": {\n                                                \"type\": \"integer\"\n                                            },\n                                            \"data2\": {\n                                                \"$ref\": \"#/definitions/model.DeepPayload\"\n                                            }\n                                        }\n                                    }\n                                ]\n                            },\n                            \"data4\": {\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"allOf\": [\n                                        {\n                                            \"$ref\": \"#/definitions/model.Payload\"\n                                        },\n                                        {\n                                            \"type\": \"object\",\n                                            \"properties\": {\n                                                \"data1\": {\n                                                    \"type\": \"array\",\n                                                    \"items\": {\n                                                        \"type\": \"integer\"\n                                                    }\n                                                },\n                                                \"data2\": {\n                                                    \"type\": \"array\",\n                                                    \"items\": {\n                                                        \"$ref\": \"#/definitions/model.DeepPayload\"\n                                                    }\n                                                }\n                                            }\n                                        }\n                                    ]\n                                }\n                            }\n                        }\n                    }\n                ]\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithNestedArrayMapFields(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {object} []map[string]model.CommonHeader{data1=[]map[string]model.Payload,data2=map[string][]int} \"Error message, if code != 200`\n\toperation := NewOperation(nil)\n\n\toperation.parser.addTestType(\"model.CommonHeader\")\n\toperation.parser.addTestType(\"model.Payload\")\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tresponse := operation.Responses.StatusCodeResponses[200]\n\tassert.Equal(t, `Error message, if code != 200`, response.Description)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"Error message, if code != 200\",\n            \"schema\": {\n                \"type\": \"array\",\n                \"items\": {\n                    \"type\": \"object\",\n                    \"additionalProperties\": {\n                        \"allOf\": [\n                            {\n                                \"$ref\": \"#/definitions/model.CommonHeader\"\n                            },\n                            {\n                                \"type\": \"object\",\n                                \"properties\": {\n                                    \"data1\": {\n                                        \"type\": \"array\",\n                                        \"items\": {\n                                            \"type\": \"object\",\n                                            \"additionalProperties\": {\n                                                \"$ref\": \"#/definitions/model.Payload\"\n                                            }\n                                        }\n                                    },\n                                    \"data2\": {\n                                        \"type\": \"object\",\n                                        \"additionalProperties\": {\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"type\": \"integer\"\n                                            }\n                                        }\n                                    }\n                                }\n                            }\n                        ]\n                    }\n                }\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithObjectTypeInSameFile(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {object} testOwner \"Error message, if code != 200\"`\n\toperation := NewOperation(nil)\n\n\toperation.parser.addTestType(\"swag.testOwner\")\n\n\tfset := token.NewFileSet()\n\tastFile, err := goparser.ParseFile(fset, \"operation_test.go\", `package swag\n\ttype testOwner struct {\n\n\t}\n\t`, goparser.ParseComments)\n\tassert.NoError(t, err)\n\n\terr = operation.ParseComment(comment, astFile)\n\tassert.NoError(t, err)\n\n\tresponse := operation.Responses.StatusCodeResponses[200]\n\tassert.Equal(t, `Error message, if code != 200`, response.Description)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"Error message, if code != 200\",\n            \"schema\": {\n                \"$ref\": \"#/definitions/swag.testOwner\"\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithObjectTypeAnonymousField(t *testing.T) {\n\t//TODO: test Anonymous\n}\n\nfunc TestParseResponseCommentWithObjectTypeErr(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {object} model.OrderRow \"Error message, if code != 200\"`\n\toperation := NewOperation(nil)\n\n\toperation.parser.addTestType(\"model.notexist\")\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.Error(t, err)\n}\n\nfunc TestParseResponseCommentWithArrayType(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {array} model.OrderRow \"Error message, if code != 200`\n\toperation := NewOperation(nil)\n\toperation.parser.addTestType(\"model.OrderRow\")\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\tresponse := operation.Responses.StatusCodeResponses[200]\n\tassert.Equal(t, `Error message, if code != 200`, response.Description)\n\tassert.Equal(t, spec.StringOrArray{\"array\"}, response.Schema.Type)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"Error message, if code != 200\",\n            \"schema\": {\n                \"type\": \"array\",\n                \"items\": {\n                    \"$ref\": \"#/definitions/model.OrderRow\"\n                }\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithBasicType(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 {string} string \"it's ok'\"`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"it's ok'\",\n            \"schema\": {\n                \"type\": \"string\"\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithBasicTypeAndCodes(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200,201,default {string} string \"it's ok\"`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"it's ok\",\n            \"schema\": {\n                \"type\": \"string\"\n            }\n        },\n        \"201\": {\n            \"description\": \"it's ok\",\n            \"schema\": {\n                \"type\": \"string\"\n            }\n        },\n        \"default\": {\n            \"description\": \"it's ok\",\n            \"schema\": {\n                \"type\": \"string\"\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseEmptyResponseComment(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200 \"it is ok\"`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"it is ok\"\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseEmptyResponseCommentWithCodes(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200,201,default \"it is ok\"`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"it is ok\"\n        },\n        \"201\": {\n            \"description\": \"it is ok\"\n        },\n        \"default\": {\n            \"description\": \"it is ok\"\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentWithHeader(t *testing.T) {\n\tt.Parallel()\n\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(`@Success 200 \"it's ok\"`, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\n\terr = operation.ParseComment(`@Header 200 {string} Token \"qwerty\"`, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\n\tb, err := json.MarshalIndent(operation, \"\", \"    \")\n\tassert.NoError(t, err)\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"it's ok\",\n            \"headers\": {\n                \"Token\": {\n                    \"type\": \"string\",\n                    \"description\": \"qwerty\"\n                }\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n\n\terr = operation.ParseComment(`@Header 200 \"Mallformed\"`, nil)\n\tassert.Error(t, err, \"ParseComment should not fail\")\n\n\terr = operation.ParseComment(`@Header 200,asdsd {string} Token \"qwerty\"`, nil)\n\tassert.Error(t, err, \"ParseComment should not fail\")\n}\n\nfunc TestParseResponseCommentWithHeaderForCodes(t *testing.T) {\n\tt.Parallel()\n\n\toperation := NewOperation(nil)\n\n\tcomment := `@Success 200,201,default \"it's ok\"`\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\n\tcomment = `@Header 200,201,default {string} Token \"qwerty\"`\n\terr = operation.ParseComment(comment, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\n\tcomment = `@Header all {string} Token2 \"qwerty\"`\n\terr = operation.ParseComment(comment, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\n\tb, err := json.MarshalIndent(operation, \"\", \"    \")\n\tassert.NoError(t, err)\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"it's ok\",\n            \"headers\": {\n                \"Token\": {\n                    \"type\": \"string\",\n                    \"description\": \"qwerty\"\n                },\n                \"Token2\": {\n                    \"type\": \"string\",\n                    \"description\": \"qwerty\"\n                }\n            }\n        },\n        \"201\": {\n            \"description\": \"it's ok\",\n            \"headers\": {\n                \"Token\": {\n                    \"type\": \"string\",\n                    \"description\": \"qwerty\"\n                },\n                \"Token2\": {\n                    \"type\": \"string\",\n                    \"description\": \"qwerty\"\n                }\n            }\n        },\n        \"default\": {\n            \"description\": \"it's ok\",\n            \"headers\": {\n                \"Token\": {\n                    \"type\": \"string\",\n                    \"description\": \"qwerty\"\n                },\n                \"Token2\": {\n                    \"type\": \"string\",\n                    \"description\": \"qwerty\"\n                }\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n\n\tcomment = `@Header 200 \"Mallformed\"`\n\terr = operation.ParseComment(comment, nil)\n\tassert.Error(t, err, \"ParseComment should not fail\")\n}\n\nfunc TestParseResponseCommentWithHeaderOnlyAll(t *testing.T) {\n\tt.Parallel()\n\n\toperation := NewOperation(nil)\n\n\tcomment := `@Success 200,201,default \"it's ok\"`\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\n\tcomment = `@Header all {string} Token \"qwerty\"`\n\terr = operation.ParseComment(comment, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\n\tb, err := json.MarshalIndent(operation, \"\", \"    \")\n\tassert.NoError(t, err)\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"it's ok\",\n            \"headers\": {\n                \"Token\": {\n                    \"type\": \"string\",\n                    \"description\": \"qwerty\"\n                }\n            }\n        },\n        \"201\": {\n            \"description\": \"it's ok\",\n            \"headers\": {\n                \"Token\": {\n                    \"type\": \"string\",\n                    \"description\": \"qwerty\"\n                }\n            }\n        },\n        \"default\": {\n            \"description\": \"it's ok\",\n            \"headers\": {\n                \"Token\": {\n                    \"type\": \"string\",\n                    \"description\": \"qwerty\"\n                }\n            }\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n\n\tcomment = `@Header 200 \"Mallformed\"`\n\terr = operation.ParseComment(comment, nil)\n\tassert.Error(t, err, \"ParseComment should not fail\")\n}\n\nfunc TestParseEmptyResponseOnlyCode(t *testing.T) {\n\tt.Parallel()\n\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(`@Success 200`, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"OK\"\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseEmptyResponseOnlyCodes(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Success 200,201,default`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err, \"ParseComment should not fail\")\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `{\n    \"responses\": {\n        \"200\": {\n            \"description\": \"OK\"\n        },\n        \"201\": {\n            \"description\": \"Created\"\n        },\n        \"default\": {\n            \"description\": \"\"\n        }\n    }\n}`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseResponseCommentParamMissing(t *testing.T) {\n\tt.Parallel()\n\n\toperation := NewOperation(nil)\n\n\tparamLenErrComment := `@Success notIntCode`\n\tparamLenErr := operation.ParseComment(paramLenErrComment, nil)\n\tassert.EqualError(t, paramLenErr, `can not parse response comment \"notIntCode\"`)\n\n\tparamLenErrComment = `@Success notIntCode {string} string \"it ok\"`\n\tparamLenErr = operation.ParseComment(paramLenErrComment, nil)\n\tassert.EqualError(t, paramLenErr, `can not parse response comment \"notIntCode {string} string \"it ok\"\"`)\n\n\tparamLenErrComment = `@Success notIntCode \"it ok\"`\n\tparamLenErr = operation.ParseComment(paramLenErrComment, nil)\n\tassert.EqualError(t, paramLenErr, `can not parse response comment \"notIntCode \"it ok\"\"`)\n}\n\nfunc TestOperation_ParseParamComment(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"integer\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfor _, paramType := range []string{\"header\", \"path\", \"query\", \"formData\"} {\n\t\t\tt.Run(paramType, func(t *testing.T) {\n\t\t\t\to := NewOperation(nil)\n\t\t\t\terr := o.ParseComment(`@Param some_id `+paramType+` int true \"Some ID\"`, nil)\n\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, o.Parameters, []spec.Parameter{{\n\t\t\t\t\tSimpleSchema: spec.SimpleSchema{\n\t\t\t\t\t\tType: \"integer\",\n\t\t\t\t\t},\n\t\t\t\t\tParamProps: spec.ParamProps{\n\t\t\t\t\t\tName:        \"some_id\",\n\t\t\t\t\t\tDescription: \"Some ID\",\n\t\t\t\t\t\tIn:          paramType,\n\t\t\t\t\t\tRequired:    true,\n\t\t\t\t\t},\n\t\t\t\t}})\n\t\t\t})\n\t\t}\n\t})\n\n\tt.Run(\"string\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfor _, paramType := range []string{\"header\", \"path\", \"query\", \"formData\"} {\n\t\t\tt.Run(paramType, func(t *testing.T) {\n\t\t\t\to := NewOperation(nil)\n\t\t\t\terr := o.ParseComment(`@Param some_string `+paramType+` string true \"Some String\"`, nil)\n\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, o.Parameters, []spec.Parameter{{\n\t\t\t\t\tSimpleSchema: spec.SimpleSchema{\n\t\t\t\t\t\tType: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\tParamProps: spec.ParamProps{\n\t\t\t\t\t\tName:        \"some_string\",\n\t\t\t\t\t\tDescription: \"Some String\",\n\t\t\t\t\t\tIn:          paramType,\n\t\t\t\t\t\tRequired:    true,\n\t\t\t\t\t},\n\t\t\t\t}})\n\t\t\t})\n\t\t}\n\t})\n\n\tt.Run(\"object\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfor _, paramType := range []string{\"header\", \"path\", \"query\", \"formData\"} {\n\t\t\tt.Run(paramType, func(t *testing.T) {\n\t\t\t\t// unknown object returns error\n\t\t\t\tassert.Error(t, NewOperation(nil).ParseComment(`@Param some_object `+paramType+` main.Object true \"Some Object\"`, nil))\n\n\t\t\t\t// verify objects are supported here\n\t\t\t\to := NewOperation(nil)\n\t\t\t\to.parser.addTestType(\"main.TestObject\")\n\t\t\t\terr := o.ParseComment(`@Param some_object `+paramType+` main.TestObject true \"Some Object\"`, nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t})\n\t\t}\n\t})\n}\n\n// Test ParseParamComment Query Params\nfunc TestParseParamCommentBodyArray(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param names body []string true \"Users List\"`\n\to := NewOperation(nil)\n\terr := o.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, o.Parameters, []spec.Parameter{{\n\t\tParamProps: spec.ParamProps{\n\t\t\tName:        \"names\",\n\t\t\tDescription: \"Users List\",\n\t\t\tIn:          \"body\",\n\t\t\tRequired:    true,\n\t\t\tSchema: &spec.Schema{\n\t\t\t\tSchemaProps: spec.SchemaProps{\n\t\t\t\t\tType: []string{\"array\"},\n\t\t\t\t\tItems: &spec.SchemaOrArray{\n\t\t\t\t\t\tSchema: &spec.Schema{\n\t\t\t\t\t\t\tSchemaProps: spec.SchemaProps{\n\t\t\t\t\t\t\t\tType: []string{\"string\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}})\n}\n\n// Test ParseParamComment Params\nfunc TestParseParamCommentArray(t *testing.T) {\n\tparamTypes := []string{\"header\", \"path\", \"query\"}\n\n\tfor _, paramType := range paramTypes {\n\t\tt.Run(paramType, func(t *testing.T) {\n\t\t\toperation := NewOperation(nil)\n\t\t\terr := operation.ParseComment(`@Param names `+paramType+` []string true \"Users List\"`, nil)\n\n\t\t\tassert.NoError(t, err)\n\n\t\t\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\t\t\texpected := `[\n    {\n        \"type\": \"array\",\n        \"items\": {\n            \"type\": \"string\"\n        },\n        \"description\": \"Users List\",\n        \"name\": \"names\",\n        \"in\": \"` + paramType + `\",\n        \"required\": true\n    }\n]`\n\t\t\tassert.Equal(t, expected, string(b))\n\n\t\t\terr = operation.ParseComment(`@Param names `+paramType+` []model.User true \"Users List\"`, nil)\n\t\t\tassert.Error(t, err)\n\t\t})\n\t}\n}\n\n// Test TestParseParamCommentDefaultValue Query Params\nfunc TestParseParamCommentDefaultValue(t *testing.T) {\n\tt.Parallel()\n\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(`@Param names query string true \"Users List\" default(test)`, nil)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"string\",\n        \"default\": \"test\",\n        \"description\": \"Users List\",\n        \"name\": \"names\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\n// Test ParseParamComment Query Params\nfunc TestParseParamCommentQueryArrayFormat(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param names query []string true \"Users List\" collectionFormat(multi)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"array\",\n        \"items\": {\n            \"type\": \"string\"\n        },\n        \"collectionFormat\": \"multi\",\n        \"description\": \"Users List\",\n        \"name\": \"names\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\n// Test ParseParamComment Query Params\nfunc TestParseParamCommentQueryArrayFormatWithStructTag(t *testing.T) {\n\tparser := New()\n\tparser.packages.ParseFile(\"test\",\n\t\t\"/test/test.go\",\n\t\t\"package test\\ntype MyQueryParams struct{Param []string `form:\\\"param\\\" collectionFormat:\\\"multi\\\"`}\",\n\t\tParseAll)\n\tparser.packages.ParseTypes()\n\tcomment := `@Param anyWhat query test.MyQueryParams true \"List\"`\n\toperation := NewOperation(parser)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"array\",\n        \"items\": {\n            \"type\": \"string\"\n        },\n        \"collectionFormat\": \"multi\",\n        \"name\": \"param\",\n        \"in\": \"query\"\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentQuerySkipWithStructTag(t *testing.T) {\n\tt.Parallel()\n\n\tparser := New()\n\tparser.packages.ParseFile(\"test\",\n\t\t\"/test/test.go\",\n\t\t\"package test\\ntype MyQueryParam struct{Param string `form:\\\"param\\\"`\\nSkipField string `form:\\\"-\\\"`}\",\n\t\tParseAll)\n\tparser.packages.ParseTypes()\n\tcomment := `@Param anyWhat query test.MyQueryParam true \"Parameter\"`\n\toperation := NewOperation(parser)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"string\",\n        \"name\": \"param\",\n        \"in\": \"query\"\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentPathWithParamTag(t *testing.T) {\n\tt.Parallel()\n\n\tparser := New()\n\tparser.packages.ParseFile(\"test\",\n\t\t\"/test/test.go\",\n\t\t\"package test\\ntype MyPathParam struct{ProjectID int `param:\\\"projectId\\\"`\\nName string `param:\\\"name\\\"`}\",\n\t\tParseAll)\n\tparser.packages.ParseTypes()\n\tcomment := `@Param anyWhat path test.MyPathParam true \"Parameter\"`\n\toperation := NewOperation(parser)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"string\",\n        \"name\": \"name\",\n        \"in\": \"path\"\n    },\n    {\n        \"type\": \"integer\",\n        \"name\": \"projectId\",\n        \"in\": \"path\"\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByID(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param unsafe_id[lte] query int true \"Unsafe query param\"`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"integer\",\n        \"description\": \"Unsafe query param\",\n        \"name\": \"unsafe_id[lte]\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentWithMultilineDescriptions(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id query int true \"First line\\nSecond line\\nThird line\"`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"integer\",\n        \"description\": \"First line\\nSecond line\\nThird line\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByQueryType(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id query int true \"Some ID\"`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"integer\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByBodyType(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id body model.OrderRow true \"Some ID\"`\n\toperation := NewOperation(nil)\n\n\toperation.parser.addTestType(\"model.OrderRow\")\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"body\",\n        \"required\": true,\n        \"schema\": {\n            \"$ref\": \"#/definitions/model.OrderRow\"\n        }\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByBodyTextPlain(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param text body string true \"Text to process\"`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"description\": \"Text to process\",\n        \"name\": \"text\",\n        \"in\": \"body\",\n        \"required\": true,\n        \"schema\": {\n            \"type\": \"string\"\n        }\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\n// TODO: fix this\nfunc TestParseParamCommentByBodyEnumsText(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param text body string true \"description\" Enums(ENUM1, ENUM2, ENUM3)`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"description\": \"description\",\n        \"name\": \"text\",\n        \"in\": \"body\",\n        \"required\": true,\n        \"schema\": {\n            \"type\": \"string\",\n            \"enum\": [\n                \"ENUM1\",\n                \"ENUM2\",\n                \"ENUM3\"\n            ]\n        }\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByBodyTypeWithDeepNestedFields(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param body body model.CommonHeader{data=string,data2=int} true \"test deep\"`\n\toperation := NewOperation(nil)\n\n\toperation.parser.addTestType(\"model.CommonHeader\")\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\tassert.Len(t, operation.Parameters, 1)\n\tassert.Equal(t, \"test deep\", operation.Parameters[0].Description)\n\tassert.True(t, operation.Parameters[0].Required)\n\n\tb, err := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\tassert.NoError(t, err)\n\texpected := `[\n    {\n        \"description\": \"test deep\",\n        \"name\": \"body\",\n        \"in\": \"body\",\n        \"required\": true,\n        \"schema\": {\n            \"allOf\": [\n                {\n                    \"$ref\": \"#/definitions/model.CommonHeader\"\n                },\n                {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"data\": {\n                            \"type\": \"string\"\n                        },\n                        \"data2\": {\n                            \"type\": \"integer\"\n                        }\n                    }\n                }\n            ]\n        }\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByBodyTypeArrayOfPrimitiveGo(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id body []int true \"Some ID\"`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"body\",\n        \"required\": true,\n        \"schema\": {\n            \"type\": \"array\",\n            \"items\": {\n                \"type\": \"integer\"\n            }\n        }\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByBodyTypeArrayOfPrimitiveGoWithDeepNestedFields(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param body body []model.CommonHeader{data=string,data2=int} true \"test deep\"`\n\toperation := NewOperation(nil)\n\toperation.parser.addTestType(\"model.CommonHeader\")\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\tassert.Len(t, operation.Parameters, 1)\n\tassert.Equal(t, \"test deep\", operation.Parameters[0].Description)\n\tassert.True(t, operation.Parameters[0].Required)\n\n\tb, err := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\tassert.NoError(t, err)\n\texpected := `[\n    {\n        \"description\": \"test deep\",\n        \"name\": \"body\",\n        \"in\": \"body\",\n        \"required\": true,\n        \"schema\": {\n            \"type\": \"array\",\n            \"items\": {\n                \"allOf\": [\n                    {\n                        \"$ref\": \"#/definitions/model.CommonHeader\"\n                    },\n                    {\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"data\": {\n                                \"type\": \"string\"\n                            },\n                            \"data2\": {\n                                \"type\": \"integer\"\n                            }\n                        }\n                    }\n                ]\n            }\n        }\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByBodyTypeErr(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id body model.OrderRow true \"Some ID\"`\n\toperation := NewOperation(nil)\n\toperation.parser.addTestType(\"model.notexist\")\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.Error(t, err)\n}\n\nfunc TestParseParamCommentByFormDataType(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param file formData file true \"this is a test file\"`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"file\",\n        \"description\": \"this is a test file\",\n        \"name\": \"file\",\n        \"in\": \"formData\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByFormDataTypeUint64(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param file formData uint64 true \"this is a test file\"`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"integer\",\n        \"format\": \"int64\",\n        \"description\": \"this is a test file\",\n        \"name\": \"file\",\n        \"in\": \"formData\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByNotSupportedType(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id not_supported int true \"Some ID\"`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.Error(t, err)\n}\n\nfunc TestParseParamCommentNotMatch(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id body mock true`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.Error(t, err)\n}\n\nfunc TestParseParamCommentByEnums(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id query string true \"Some ID\" Enums(A, B, C)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"enum\": [\n            \"A\",\n            \"B\",\n            \"C\"\n        ],\n        \"type\": \"string\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n\n\tcomment = `@Param some_id query int true \"Some ID\" Enums(1, 2, 3)`\n\toperation = NewOperation(nil)\n\terr = operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ = json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected = `[\n    {\n        \"enum\": [\n            1,\n            2,\n            3\n        ],\n        \"type\": \"integer\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n\n\tcomment = `@Param some_id query number true \"Some ID\" Enums(1.1, 2.2, 3.3)`\n\toperation = NewOperation(nil)\n\terr = operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ = json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected = `[\n    {\n        \"enum\": [\n            1.1,\n            2.2,\n            3.3\n        ],\n        \"type\": \"number\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n\n\tcomment = `@Param some_id query bool true \"Some ID\" Enums(true, false)`\n\toperation = NewOperation(nil)\n\terr = operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ = json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected = `[\n    {\n        \"enum\": [\n            true,\n            false\n        ],\n        \"type\": \"boolean\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n\n\toperation = NewOperation(nil)\n\n\tcomment = `@Param some_id query int true \"Some ID\" Enums(A, B, C)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n\n\tcomment = `@Param some_id query number true \"Some ID\" Enums(A, B, C)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n\n\tcomment = `@Param some_id query boolean true \"Some ID\" Enums(A, B, C)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n\n\tcomment = `@Param some_id query Document true \"Some ID\" Enums(A, B, C)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n}\n\nfunc TestParseParamCommentByMaxLength(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id query string true \"Some ID\" MaxLength(10)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"maxLength\": 10,\n        \"type\": \"string\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n\n\tcomment = `@Param some_id query int true \"Some ID\" MaxLength(10)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n\n\tcomment = `@Param some_id query string true \"Some ID\" MaxLength(Goopher)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n}\n\nfunc TestParseParamCommentByMinLength(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id query string true \"Some ID\" MinLength(10)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"minLength\": 10,\n        \"type\": \"string\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n\n\tcomment = `@Param some_id query int true \"Some ID\" MinLength(10)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n\n\tcomment = `@Param some_id query string true \"Some ID\" MinLength(Goopher)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n}\n\nfunc TestParseParamCommentByMinimum(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id query int true \"Some ID\" Minimum(10)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"minimum\": 10,\n        \"type\": \"integer\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n\n\tcomment = `@Param some_id query int true \"Some ID\" Mininum(10)`\n\tassert.NoError(t, operation.ParseComment(comment, nil))\n\n\tcomment = `@Param some_id query string true \"Some ID\" Minimum(10)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n\n\tcomment = `@Param some_id query integer true \"Some ID\" Minimum(Goopher)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n}\n\nfunc TestParseParamCommentByMaximum(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id query int true \"Some ID\" Maximum(10)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"maximum\": 10,\n        \"type\": \"integer\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n\n\tcomment = `@Param some_id query int true \"Some ID\" Maxinum(10)`\n\tassert.NoError(t, operation.ParseComment(comment, nil))\n\n\tcomment = `@Param some_id query string true \"Some ID\" Maximum(10)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n\n\tcomment = `@Param some_id query integer true \"Some ID\" Maximum(Goopher)`\n\tassert.Error(t, operation.ParseComment(comment, nil))\n}\n\nfunc TestParseParamCommentByDefault(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id query int true \"Some ID\" Default(10)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"integer\",\n        \"default\": 10,\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByExampleInt(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id query int true \"Some ID\" Example(10)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"integer\",\n        \"example\": 10,\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByExampleString(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id query string true \"Some ID\" Example(True feelings)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"string\",\n        \"example\": \"True feelings\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByExampleStringComplex(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id query string true \"Some ID\" Example(user_id.eq(1))`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"string\",\n        \"example\": \"user_id.eq(1)\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentByExampleUnsupportedType(t *testing.T) {\n\tt.Parallel()\n\tvar param spec.Parameter\n\n\tsetExample(&param, \"something\", \"random value\")\n\tassert.Equal(t, param.Example, nil)\n\n\tsetExample(&param, STRING, \"string value\")\n\tassert.Equal(t, param.Example, \"string value\")\n\n\tsetExample(&param, INTEGER, \"10\")\n\tassert.Equal(t, param.Example, 10)\n\n\tsetExample(&param, NUMBER, \"10\")\n\tassert.Equal(t, param.Example, float64(10))\n}\n\nfunc TestParseParamCommentBySchemaExampleString(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param some_id body string true \"Some ID\" SchemaExample(True feelings)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"body\",\n        \"required\": true,\n        \"schema\": {\n            \"type\": \"string\",\n            \"example\": \"True feelings\"\n        }\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentBySchemaExampleUnsupportedType(t *testing.T) {\n\tt.Parallel()\n\tvar param spec.Parameter\n\n\tsetSchemaExample(&param, \"something\", \"random value\")\n\tassert.Nil(t, param.Schema)\n\n\tsetSchemaExample(&param, STRING, \"string value\")\n\tassert.Nil(t, param.Schema)\n\n\tparam.Schema = &spec.Schema{}\n\tsetSchemaExample(&param, STRING, \"string value\")\n\tassert.Equal(t, \"string value\", param.Schema.Example)\n\n\tsetSchemaExample(&param, INTEGER, \"10\")\n\tassert.Equal(t, 10, param.Schema.Example)\n\n\tsetSchemaExample(&param, NUMBER, \"10\")\n\tassert.Equal(t, float64(10), param.Schema.Example)\n\n\tsetSchemaExample(&param, STRING, \"string \\\\r\\\\nvalue\")\n\tassert.Equal(t, \"string \\r\\nvalue\", param.Schema.Example)\n}\n\nfunc TestParseParamArrayWithEnums(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Param field query []string true \"An enum collection\" collectionFormat(csv) enums(also,valid)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"array\",\n        \"items\": {\n            \"enum\": [\n                \"also\",\n                \"valid\"\n            ],\n            \"type\": \"string\"\n        },\n        \"collectionFormat\": \"csv\",\n        \"description\": \"An enum collection\",\n        \"name\": \"field\",\n        \"in\": \"query\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseAndExtractionParamAttribute(t *testing.T) {\n\tt.Parallel()\n\n\top := NewOperation(nil)\n\tnumberParam := spec.Parameter{}\n\terr := op.parseParamAttribute(\n\t\t\" default(1) maximum(100) minimum(0) format(csv)\",\n\t\t\"\",\n\t\tNUMBER,\n\t\t\"\",\n\t\t&numberParam,\n\t)\n\tassert.NoError(t, err)\n\tassert.Equal(t, float64(0), *numberParam.Minimum)\n\tassert.Equal(t, float64(100), *numberParam.Maximum)\n\tassert.Equal(t, \"csv\", numberParam.SimpleSchema.Format)\n\tassert.Equal(t, float64(1), numberParam.Default)\n\n\terr = op.parseParamAttribute(\" minlength(1)\", \"\", NUMBER, \"\", nil)\n\tassert.Error(t, err)\n\n\terr = op.parseParamAttribute(\" maxlength(1)\", \"\", NUMBER, \"\", nil)\n\tassert.Error(t, err)\n\n\tstringParam := spec.Parameter{}\n\terr = op.parseParamAttribute(\n\t\t\" default(test) maxlength(100) minlength(0) format(csv)\",\n\t\t\"\",\n\t\tSTRING,\n\t\t\"\",\n\t\t&stringParam,\n\t)\n\tassert.NoError(t, err)\n\tassert.Equal(t, int64(0), *stringParam.MinLength)\n\tassert.Equal(t, int64(100), *stringParam.MaxLength)\n\tassert.Equal(t, \"csv\", stringParam.SimpleSchema.Format)\n\terr = op.parseParamAttribute(\" minimum(0)\", \"\", STRING, \"\", nil)\n\tassert.Error(t, err)\n\n\terr = op.parseParamAttribute(\" maximum(0)\", \"\", STRING, \"\", nil)\n\tassert.Error(t, err)\n\n\tarrayParram := spec.Parameter{}\n\terr = op.parseParamAttribute(\" collectionFormat(tsv)\", ARRAY, STRING, \"\", &arrayParram)\n\tassert.Equal(t, \"tsv\", arrayParram.CollectionFormat)\n\tassert.NoError(t, err)\n\n\terr = op.parseParamAttribute(\" collectionFormat(tsv)\", STRING, STRING, \"\", nil)\n\tassert.Error(t, err)\n\n\terr = op.parseParamAttribute(\" default(0)\", \"\", ARRAY, \"\", nil)\n\tassert.NoError(t, err)\n}\n\nfunc TestParseParamCommentByExtensions(t *testing.T) {\n\tcomment := `@Param some_id path int true \"Some ID\" extensions(x-example=test,x-custom=Goopher,x-custom2)`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(operation.Parameters, \"\", \"    \")\n\texpected := `[\n    {\n        \"type\": \"integer\",\n        \"x-custom\": \"Goopher\",\n        \"x-custom2\": true,\n        \"x-example\": \"test\",\n        \"description\": \"Some ID\",\n        \"name\": \"some_id\",\n        \"in\": \"path\",\n        \"required\": true\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamStructCodeExample(t *testing.T) {\n\tt.Parallel()\n\n\tfset := token.NewFileSet()\n\tast, err := goparser.ParseFile(fset, \"operation_test.go\", `package swag\n\timport structs \"github.com/swaggo/swag/testdata/param_structs\"\n\t`, goparser.ParseComments)\n\tassert.NoError(t, err)\n\n\tparser := New()\n\terr = parser.parseFile(\"github.com/swaggo/swag/testdata/param_structs\", \"testdata/param_structs/structs.go\", nil, ParseModels)\n\tassert.NoError(t, err)\n\t_, err = parser.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\tvalidateParameters := func(operation *Operation, params ...spec.Parameter) {\n\t\tassert.Equal(t, len(params), len(operation.Parameters))\n\n\t\tfor _, param := range params {\n\t\t\tfound := false\n\t\t\tfor _, p := range operation.Parameters {\n\t\t\t\tif p.Name == param.Name {\n\t\t\t\t\tassert.Equal(t, param.ParamProps, p.ParamProps)\n\t\t\t\t\tassert.Equal(t, param.CommonValidations, p.CommonValidations)\n\t\t\t\t\tassert.Equal(t, param.SimpleSchema, p.SimpleSchema)\n\t\t\t\t\tfound = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tassert.True(t, found, \"found parameter %s\", param.Name)\n\t\t}\n\t}\n\n\t// values used in validation checks\n\tmax := float64(10)\n\tmaxLen := int64(10)\n\tmin := float64(0)\n\n\t// query and form behave the same\n\tfor _, param := range []string{\"query\", \"formData\"} {\n\t\tt.Run(param+\" struct\", func(t *testing.T) {\n\t\t\toperation := NewOperation(parser)\n\t\t\tcomment := fmt.Sprintf(`@Param model %s structs.FormModel true \"query params\"`, param)\n\t\t\terr = operation.ParseComment(comment, ast)\n\t\t\tassert.NoError(t, err)\n\n\t\t\tvalidateParameters(operation,\n\t\t\t\tspec.Parameter{\n\t\t\t\t\tParamProps: spec.ParamProps{\n\t\t\t\t\t\tName:        \"f\",\n\t\t\t\t\t\tDescription: \"\",\n\t\t\t\t\t\tIn:          param,\n\t\t\t\t\t\tRequired:    true,\n\t\t\t\t\t},\n\t\t\t\t\tCommonValidations: spec.CommonValidations{\n\t\t\t\t\t\tMaxLength: &maxLen,\n\t\t\t\t\t},\n\t\t\t\t\tSimpleSchema: spec.SimpleSchema{\n\t\t\t\t\t\tType: \"string\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tspec.Parameter{\n\t\t\t\t\tParamProps: spec.ParamProps{\n\t\t\t\t\t\tName:        \"b\",\n\t\t\t\t\t\tDescription: \"B is another field\",\n\t\t\t\t\t\tIn:          param,\n\t\t\t\t\t},\n\t\t\t\t\tSimpleSchema: spec.SimpleSchema{\n\t\t\t\t\t\tType: \"boolean\",\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t})\n\t}\n\n\tt.Run(\"header struct\", func(t *testing.T) {\n\t\toperation := NewOperation(parser)\n\t\tcomment := `@Param auth header structs.AuthHeader true \"auth header\"`\n\t\terr = operation.ParseComment(comment, ast)\n\t\tassert.NoError(t, err)\n\n\t\tvalidateParameters(operation,\n\t\t\tspec.Parameter{\n\t\t\t\tParamProps: spec.ParamProps{\n\t\t\t\t\tName:        \"X-Auth-Token\",\n\t\t\t\t\tDescription: \"Token is the auth token\",\n\t\t\t\t\tIn:          \"header\",\n\t\t\t\t\tRequired:    true,\n\t\t\t\t},\n\t\t\t\tSimpleSchema: spec.SimpleSchema{\n\t\t\t\t\tType: \"string\",\n\t\t\t\t},\n\t\t\t}, spec.Parameter{\n\t\t\t\tParamProps: spec.ParamProps{\n\t\t\t\t\tName:        \"anotherHeader\",\n\t\t\t\t\tDescription: \"AnotherHeader is another header\",\n\t\t\t\t\tIn:          \"header\",\n\t\t\t\t},\n\t\t\t\tCommonValidations: spec.CommonValidations{\n\t\t\t\t\tMaximum: &max,\n\t\t\t\t\tMinimum: &min,\n\t\t\t\t},\n\t\t\t\tSimpleSchema: spec.SimpleSchema{\n\t\t\t\t\tType: \"integer\",\n\t\t\t\t},\n\t\t\t})\n\t})\n\n\tt.Run(\"path struct\", func(t *testing.T) {\n\t\toperation := NewOperation(parser)\n\t\tcomment := `@Param path path structs.PathModel true \"path params\"`\n\t\terr = operation.ParseComment(comment, ast)\n\t\tassert.NoError(t, err)\n\n\t\tvalidateParameters(operation,\n\t\t\tspec.Parameter{\n\t\t\t\tParamProps: spec.ParamProps{\n\t\t\t\t\tName:        \"id\",\n\t\t\t\t\tDescription: \"ID is the id\",\n\t\t\t\t\tIn:          \"path\",\n\t\t\t\t\tRequired:    true,\n\t\t\t\t},\n\t\t\t\tSimpleSchema: spec.SimpleSchema{\n\t\t\t\t\tType: \"integer\",\n\t\t\t\t},\n\t\t\t}, spec.Parameter{\n\t\t\t\tParamProps: spec.ParamProps{\n\t\t\t\t\tName:        \"name\",\n\t\t\t\t\tDescription: \"\",\n\t\t\t\t\tIn:          \"path\",\n\t\t\t\t},\n\t\t\t\tCommonValidations: spec.CommonValidations{\n\t\t\t\t\tMaxLength: &maxLen,\n\t\t\t\t},\n\t\t\t\tSimpleSchema: spec.SimpleSchema{\n\t\t\t\t\tType: \"string\",\n\t\t\t\t},\n\t\t\t})\n\t})\n}\n\nfunc TestParseIdComment(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Id myOperationId`\n\toperation := NewOperation(nil)\n\terr := operation.ParseComment(comment, nil)\n\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"myOperationId\", operation.ID)\n}\n\nfunc TestFindTypeDefCoreLib(t *testing.T) {\n\tt.Parallel()\n\n\ts, err := findTypeDef(\"net/http\", \"Request\")\n\tassert.NoError(t, err)\n\tassert.NotNil(t, s)\n}\n\nfunc TestFindTypeDefExternalPkg(t *testing.T) {\n\tt.Parallel()\n\n\ts, err := findTypeDef(\"github.com/KyleBanks/depth\", \"Tree\")\n\tassert.NoError(t, err)\n\tassert.NotNil(t, s)\n}\n\nfunc TestFindTypeDefInvalidPkg(t *testing.T) {\n\tt.Parallel()\n\n\ts, err := findTypeDef(\"does-not-exist\", \"foo\")\n\tassert.Error(t, err)\n\tassert.Nil(t, s)\n}\n\nfunc TestParseSecurityComment(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Security OAuth2Implicit[read, write]`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, operation.Security, []map[string][]string{\n\t\t{\n\t\t\t\"OAuth2Implicit\": {\"read\", \"write\"},\n\t\t},\n\t})\n}\n\nfunc TestParseSecurityCommentSimple(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Security ApiKeyAuth`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, operation.Security, []map[string][]string{\n\t\t{\n\t\t\t\"ApiKeyAuth\": {},\n\t\t},\n\t})\n}\n\nfunc TestParseSecurityCommentAnd(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Security OAuth2Implicit[read, write] && Firebase[]`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\texpect := []map[string][]string{\n\t\t{\n\t\t\t\"OAuth2Implicit\": {\"read\", \"write\"},\n\t\t\t\"Firebase\":       {\"\"},\n\t\t},\n\t}\n\tassert.Equal(t, operation.Security, expect)\n\n\toldVersionComment := `@Security OAuth2Implicit[read, write] || Firebase[]`\n\toperation = NewOperation(nil)\n\terr = operation.ParseComment(oldVersionComment, nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, operation.Security, expect)\n}\n\nfunc TestParseMultiDescription(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Description line one`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tcomment = `@Tags multi`\n\terr = operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tcomment = `@Description line two x`\n\terr = operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(operation, \"\", \"    \")\n\n\texpected := `\"description\": \"line one\\nline two x\"`\n\tassert.Contains(t, string(b), expected)\n}\n\nfunc TestParseDescriptionMarkdown(t *testing.T) {\n\tt.Parallel()\n\n\toperation := NewOperation(nil)\n\toperation.parser.markdownFileDir = \"example/markdown\"\n\n\tcomment := `@description.markdown admin.md`\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tcomment = `@description.markdown missing.md`\n\n\terr = operation.ParseComment(comment, nil)\n\tassert.Error(t, err)\n}\n\nfunc TestParseSummary(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@summary line one`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tcomment = `@Summary line one`\n\terr = operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n}\n\nfunc TestParseDeprecationDescription(t *testing.T) {\n\tt.Parallel()\n\n\tcomment := `@Deprecated`\n\toperation := NewOperation(nil)\n\n\terr := operation.ParseComment(comment, nil)\n\tassert.NoError(t, err)\n\n\tif !operation.Deprecated {\n\t\tt.Error(\"Failed to parse @deprecated comment\")\n\t}\n}\n\nfunc TestParseExtentions(t *testing.T) {\n\tt.Parallel()\n\t// Fail if there are no args for attributes.\n\t{\n\t\tcomment := `@x-amazon-apigateway-integration`\n\t\toperation := NewOperation(nil)\n\n\t\terr := operation.ParseComment(comment, nil)\n\t\tassert.EqualError(t, err, \"annotation @x-amazon-apigateway-integration need a value\")\n\t}\n\n\t// Fail if args of attributes are broken.\n\t{\n\t\tcomment := `@x-amazon-apigateway-integration [\"broken\"}]`\n\t\toperation := NewOperation(nil)\n\n\t\terr := operation.ParseComment(comment, nil)\n\t\tassert.EqualError(t, err, \"annotation @x-amazon-apigateway-integration need a valid json value\")\n\t}\n\n\t// OK\n\t{\n\t\tcomment := `@x-amazon-apigateway-integration {\"uri\": \"${some_arn}\", \"passthroughBehavior\": \"when_no_match\", \"httpMethod\": \"POST\", \"type\": \"aws_proxy\"}`\n\t\toperation := NewOperation(nil)\n\n\t\terr := operation.ParseComment(comment, nil)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, operation.Extensions[\"x-amazon-apigateway-integration\"],\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"httpMethod\":          \"POST\",\n\t\t\t\t\"passthroughBehavior\": \"when_no_match\",\n\t\t\t\t\"type\":                \"aws_proxy\",\n\t\t\t\t\"uri\":                 \"${some_arn}\",\n\t\t\t})\n\t}\n\n\t// Test x-tagGroups\n\t{\n\t\tcomment := `@x-tagGroups [{\"name\":\"Natural Persons\",\"tags\":[\"Person\",\"PersonRisk\",\"PersonDocuments\"]}]`\n\t\toperation := NewOperation(nil)\n\n\t\terr := operation.ParseComment(comment, nil)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, operation.Extensions[\"x-tagGroups\"],\n\t\t\t[]interface{}{map[string]interface{}{\n\t\t\t\t\"name\": \"Natural Persons\",\n\t\t\t\t\"tags\": []interface{}{\n\t\t\t\t\t\"Person\",\n\t\t\t\t\t\"PersonRisk\",\n\t\t\t\t\t\"PersonDocuments\",\n\t\t\t\t},\n\t\t\t}})\n\t}\n}\n\nfunc TestFindInSlice(t *testing.T) {\n\tt.Parallel()\n\n\tassert.True(t, findInSlice([]string{\"one\", \"two\", \"tree\"}, \"one\"))\n\tassert.True(t, findInSlice([]string{\"tree\", \"two\", \"one\"}, \"one\"))\n\tassert.True(t, findInSlice([]string{\"two\", \"one\", \"tree\"}, \"one\"))\n\tassert.False(t, findInSlice([]string{\"one\", \"two\", \"tree\"}, \"four\"))\n}\n\nfunc TestParseResponseHeaderComment(t *testing.T) {\n\tt.Parallel()\n\n\toperation := NewOperation(nil)\n\toperation.Responses = &spec.Responses{}\n\terr := operation.ParseResponseComment(`default {string} string \"other error\"`, nil)\n\tassert.NoError(t, err)\n\terr = operation.ParseResponseHeaderComment(`all {string} Token \"qwerty\"`, nil)\n\tassert.NoError(t, err)\n}\n\nfunc TestParseObjectSchema(t *testing.T) {\n\tt.Parallel()\n\n\toperation := NewOperation(nil)\n\n\tschema, err := operation.parseObjectSchema(\"interface{}\", nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema, &spec.Schema{})\n\n\tschema, err = operation.parseObjectSchema(\"any\", nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema, &spec.Schema{})\n\n\tschema, err = operation.parseObjectSchema(\"any{data=string}\", nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema,\n\t\t(&spec.Schema{}).WithAllOf(spec.Schema{}, *PrimitiveSchema(OBJECT).SetProperty(\"data\", *PrimitiveSchema(\"string\"))))\n\n\tschema, err = operation.parseObjectSchema(\"int\", nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema, PrimitiveSchema(INTEGER))\n\n\tschema, err = operation.parseObjectSchema(\"[]string\", nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema, spec.ArrayProperty(PrimitiveSchema(STRING)))\n\n\tschema, err = operation.parseObjectSchema(\"[]int\", nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema, spec.ArrayProperty(PrimitiveSchema(INTEGER)))\n\n\t_, err = operation.parseObjectSchema(\"[]bleah\", nil)\n\tassert.Error(t, err)\n\n\tschema, err = operation.parseObjectSchema(\"map[]string\", nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema, spec.MapProperty(PrimitiveSchema(STRING)))\n\n\tschema, err = operation.parseObjectSchema(\"map[]int\", nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema, spec.MapProperty(PrimitiveSchema(INTEGER)))\n\n\tschema, err = operation.parseObjectSchema(\"map[]interface{}\", nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema, spec.MapProperty(nil))\n\n\t_, err = operation.parseObjectSchema(\"map[string\", nil)\n\tassert.Error(t, err)\n\n\t_, err = operation.parseObjectSchema(\"map[]bleah\", nil)\n\tassert.Error(t, err)\n\n\toperation.parser = New()\n\toperation.parser.packages = &PackagesDefinitions{\n\t\tuniqueDefinitions: map[string]*TypeSpecDef{\n\t\t\t\"model.User\": {\n\t\t\t\tFile: &ast.File{\n\t\t\t\t\tName: &ast.Ident{\n\t\t\t\t\t\tName: \"user.go\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tTypeSpec: &ast.TypeSpec{\n\t\t\t\t\tName: &ast.Ident{\n\t\t\t\t\t\tName: \"User\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\t_, err = operation.parseObjectSchema(\"model.User\", nil)\n\tassert.NoError(t, err)\n\n\toperation.parser = nil\n\tschema, err = operation.parseObjectSchema(\"user.Model\", nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema, RefSchema(\"user.Model\"))\n}\n\nfunc TestParseCodeSamples(t *testing.T) {\n\tt.Parallel()\n\tconst comment = `@x-codeSamples file`\n\tt.Run(\"Find sample by file\", func(t *testing.T) {\n\n\t\toperation := NewOperation(nil, SetCodeExampleFilesDirectory(\"testdata/code_examples\"))\n\t\toperation.Summary = \"example\"\n\n\t\terr := operation.ParseComment(comment, nil)\n\t\tassert.NoError(t, err, \"no error should be thrown\")\n\t\tassert.Equal(t, operation.Summary, \"example\")\n\t\tassert.Equal(t, operation.Extensions[\"x-codeSamples\"],\n\t\t\tmap[string]interface{}{\"lang\": \"JavaScript\", \"source\": \"console.log('Hello World');\"})\n\t})\n\n\tt.Run(\"With broken file sample\", func(t *testing.T) {\n\t\toperation := NewOperation(nil, SetCodeExampleFilesDirectory(\"testdata/code_examples\"))\n\t\toperation.Summary = \"broken\"\n\n\t\terr := operation.ParseComment(comment, nil)\n\t\tassert.Error(t, err, \"no error should be thrown\")\n\t})\n\n\tt.Run(\"Example file not found\", func(t *testing.T) {\n\t\toperation := NewOperation(nil, SetCodeExampleFilesDirectory(\"testdata/code_examples\"))\n\t\toperation.Summary = \"badExample\"\n\n\t\terr := operation.ParseComment(comment, nil)\n\t\tassert.Error(t, err, \"error was expected, as file does not exist\")\n\t})\n\n\tt.Run(\"Without line reminder\", func(t *testing.T) {\n\t\tcomment := `@x-codeSamples`\n\t\toperation := NewOperation(nil, SetCodeExampleFilesDirectory(\"testdata/code_examples\"))\n\t\toperation.Summary = \"example\"\n\n\t\terr := operation.ParseComment(comment, nil)\n\t\tassert.Error(t, err, \"no error should be thrown\")\n\t})\n\n\tt.Run(\" broken dir\", func(t *testing.T) {\n\t\toperation := NewOperation(nil, SetCodeExampleFilesDirectory(\"testdata/fake_examples\"))\n\t\toperation.Summary = \"code\"\n\n\t\terr := operation.ParseComment(comment, nil)\n\t\tassert.Error(t, err, \"no error should be thrown\")\n\t})\n}\n\nfunc TestParseDeprecatedRouter(t *testing.T) {\n\tp := New()\n\tsearchDir := \"./testdata/deprecated_router\"\n\tif err := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth); err != nil {\n\t\tt.Error(\"Failed to parse api: \" + err.Error())\n\t}\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\tassert.Equal(t, expected, b)\n}\n"
  },
  {
    "path": "package.go",
    "content": "package swag\n\nimport (\n\t\"go/ast\"\n\t\"go/token\"\n\t\"reflect\"\n\t\"strconv\"\n\n\t\"golang.org/x/tools/go/packages\"\n)\n\n// PackageDefinitions files and definition in a package.\ntype PackageDefinitions struct {\n\t// files in this package, map key is file's relative path starting package path\n\tFiles map[string]*ast.File\n\n\t// definitions in this package, map key is typeName\n\tTypeDefinitions map[string]*TypeSpecDef\n\n\t// const variables in this package, map key is the name\n\tConstTable map[string]*ConstVariable\n\n\t// const variables in order in this package\n\tOrderedConst []*ConstVariable\n\n\t// package name\n\tName string\n\n\t// package path\n\tPath string\n\n\tPackage *packages.Package\n}\n\n// ConstVariableGlobalEvaluator an interface used to evaluate enums across packages\ntype ConstVariableGlobalEvaluator interface {\n\tEvaluateConstValue(pkg *PackageDefinitions, cv *ConstVariable, recursiveStack map[string]struct{}) (any, ast.Expr)\n\tEvaluateConstValueByName(file *ast.File, pkgPath, constVariableName string, recursiveStack map[string]struct{}) (any, ast.Expr)\n\tFindTypeSpec(typeName string, file *ast.File) *TypeSpecDef\n}\n\n// NewPackageDefinitions new a PackageDefinitions object\nfunc NewPackageDefinitions(name, pkgPath string) *PackageDefinitions {\n\treturn &PackageDefinitions{\n\t\tName:            name,\n\t\tPath:            pkgPath,\n\t\tFiles:           make(map[string]*ast.File),\n\t\tTypeDefinitions: make(map[string]*TypeSpecDef),\n\t\tConstTable:      make(map[string]*ConstVariable),\n\t}\n}\n\n// AddFile add a file\nfunc (pkg *PackageDefinitions) AddFile(pkgPath string, file *ast.File) *PackageDefinitions {\n\tpkg.Files[pkgPath] = file\n\treturn pkg\n}\n\n// AddTypeSpec add a type spec.\nfunc (pkg *PackageDefinitions) AddTypeSpec(name string, typeSpec *TypeSpecDef) *PackageDefinitions {\n\tpkg.TypeDefinitions[name] = typeSpec\n\treturn pkg\n}\n\n// AddConst add a const variable.\nfunc (pkg *PackageDefinitions) AddConst(astFile *ast.File, valueSpec *ast.ValueSpec) *PackageDefinitions {\n\tfor i := 0; i < len(valueSpec.Names) && i < len(valueSpec.Values); i++ {\n\t\tvariable := &ConstVariable{\n\t\t\tName:  valueSpec.Names[i],\n\t\t\tType:  valueSpec.Type,\n\t\t\tValue: valueSpec.Values[i],\n\t\t\tFile:  astFile,\n\t\t}\n\t\t//take the nearest line as comment from comment list or doc list. comment list first.\n\t\tif valueSpec.Comment != nil && len(valueSpec.Comment.List) > 0 {\n\t\t\tvariable.Comment = valueSpec.Comment.List[0].Text\n\t\t} else if valueSpec.Doc != nil && len(valueSpec.Doc.List) > 0 {\n\t\t\tvariable.Comment = valueSpec.Doc.List[len(valueSpec.Doc.List)-1].Text\n\t\t}\n\t\tpkg.ConstTable[valueSpec.Names[i].Name] = variable\n\t\tpkg.OrderedConst = append(pkg.OrderedConst, variable)\n\t}\n\treturn pkg\n}\n\nfunc (pkg *PackageDefinitions) evaluateConstValue(file *ast.File, iota int, expr ast.Expr, globalEvaluator ConstVariableGlobalEvaluator, recursiveStack map[string]struct{}) (any, ast.Expr) {\n\tswitch valueExpr := expr.(type) {\n\tcase *ast.Ident:\n\t\tif valueExpr.Name == \"iota\" {\n\t\t\treturn iota, nil\n\t\t}\n\t\tif pkg.ConstTable != nil {\n\t\t\tif cv, ok := pkg.ConstTable[valueExpr.Name]; ok {\n\t\t\t\treturn globalEvaluator.EvaluateConstValue(pkg, cv, recursiveStack)\n\t\t\t}\n\t\t}\n\tcase *ast.SelectorExpr:\n\t\tpkgIdent, ok := valueExpr.X.(*ast.Ident)\n\t\tif !ok {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn globalEvaluator.EvaluateConstValueByName(file, pkgIdent.Name, valueExpr.Sel.Name, recursiveStack)\n\tcase *ast.BasicLit:\n\t\tswitch valueExpr.Kind {\n\t\tcase token.INT:\n\t\t\t//a basic literal integer is int type in default, or must have an explicit converting type in front\n\t\t\tif x, err := strconv.ParseInt(valueExpr.Value, 0, 64); err == nil {\n\t\t\t\treturn int(x), nil\n\t\t\t} else if x, err := strconv.ParseUint(valueExpr.Value, 0, 64); err == nil {\n\t\t\t\treturn x, nil\n\t\t\t} else {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\tcase token.STRING:\n\t\t\tif valueExpr.Value[0] == '`' {\n\t\t\t\treturn valueExpr.Value[1 : len(valueExpr.Value)-1], nil\n\t\t\t}\n\t\t\treturn EvaluateEscapedString(valueExpr.Value[1 : len(valueExpr.Value)-1]), nil\n\t\tcase token.CHAR:\n\t\t\treturn EvaluateEscapedChar(valueExpr.Value[1 : len(valueExpr.Value)-1]), nil\n\t\t}\n\tcase *ast.UnaryExpr:\n\t\tx, evalType := pkg.evaluateConstValue(file, iota, valueExpr.X, globalEvaluator, recursiveStack)\n\t\tif x == nil {\n\t\t\treturn x, evalType\n\t\t}\n\t\treturn EvaluateUnary(x, valueExpr.Op, evalType)\n\tcase *ast.BinaryExpr:\n\t\tx, evalTypex := pkg.evaluateConstValue(file, iota, valueExpr.X, globalEvaluator, recursiveStack)\n\t\ty, evalTypey := pkg.evaluateConstValue(file, iota, valueExpr.Y, globalEvaluator, recursiveStack)\n\t\tif x == nil || y == nil {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn EvaluateBinary(x, y, valueExpr.Op, evalTypex, evalTypey)\n\tcase *ast.ParenExpr:\n\t\treturn pkg.evaluateConstValue(file, iota, valueExpr.X, globalEvaluator, recursiveStack)\n\tcase *ast.CallExpr:\n\t\t//data conversion\n\t\tif len(valueExpr.Args) != 1 {\n\t\t\treturn nil, nil\n\t\t}\n\t\targ := valueExpr.Args[0]\n\t\tif ident, ok := valueExpr.Fun.(*ast.Ident); ok {\n\t\t\tname := ident.Name\n\t\t\tif name == \"uintptr\" {\n\t\t\t\tname = \"uint\"\n\t\t\t}\n\t\t\tvalue, _ := pkg.evaluateConstValue(file, iota, arg, globalEvaluator, recursiveStack)\n\t\t\tif IsGolangPrimitiveType(name) {\n\t\t\t\tvalue = EvaluateDataConversion(value, name)\n\t\t\t\treturn value, nil\n\t\t\t} else if name == \"len\" {\n\t\t\t\treturn reflect.ValueOf(value).Len(), nil\n\t\t\t}\n\t\t\ttypeDef := globalEvaluator.FindTypeSpec(name, file)\n\t\t\tif typeDef == nil {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\t\t\treturn value, valueExpr.Fun\n\t\t} else if selector, ok := valueExpr.Fun.(*ast.SelectorExpr); ok {\n\t\t\ttypeDef := globalEvaluator.FindTypeSpec(fullTypeName(selector.X.(*ast.Ident).Name, selector.Sel.Name), file)\n\t\t\tif typeDef == nil {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\t\t\treturn arg, typeDef.TypeSpec.Type\n\t\t}\n\t}\n\treturn nil, nil\n}\n"
  },
  {
    "path": "packages.go",
    "content": "package swag\n\nimport (\n\t\"fmt\"\n\t\"go/ast\"\n\t\"go/constant\"\n\tgoparser \"go/parser\"\n\t\"go/token\"\n\t\"go/types\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"slices\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"golang.org/x/tools/go/loader\"\n\t\"golang.org/x/tools/go/packages\"\n)\n\n// PackagesDefinitions map[package import path]*PackageDefinitions.\ntype PackagesDefinitions struct {\n\tfiles             map[*ast.File]*AstFileInfo\n\tpackages          map[string]*PackageDefinitions\n\tuniqueDefinitions map[string]*TypeSpecDef\n\tparseDependency   ParseFlag\n\tdebug             Debugger\n}\n\n// NewPackagesDefinitions create object PackagesDefinitions.\nfunc NewPackagesDefinitions() *PackagesDefinitions {\n\treturn &PackagesDefinitions{\n\t\tfiles:             make(map[*ast.File]*AstFileInfo),\n\t\tpackages:          make(map[string]*PackageDefinitions),\n\t\tuniqueDefinitions: make(map[string]*TypeSpecDef),\n\t}\n}\n\n// AddPackages store packages.Package to PackagesDefinitions.\nfunc (pkgDefs *PackagesDefinitions) AddPackages(pkgs []*packages.Package) {\n\tfor _, pkg := range pkgs {\n\t\tpkgDef, ok := pkgDefs.packages[pkg.PkgPath]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tif pkgDef.Package != nil {\n\t\t\tcontinue\n\t\t}\n\t\tpkgDef.Package = pkg\n\t\timports := make([]*packages.Package, 0, len(pkg.Imports))\n\t\tfor _, dep := range pkg.Imports {\n\t\t\timports = append(imports, dep)\n\t\t}\n\t\tpkgDefs.AddPackages(imports)\n\t}\n}\n\n// ParseFile parse a source file.\nfunc (pkgDefs *PackagesDefinitions) ParseFile(packageDir, path string, src any, flag ParseFlag) error {\n\t// positions are relative to FileSet\n\tfileSet := token.NewFileSet()\n\tastFile, err := goparser.ParseFile(fileSet, path, src, goparser.ParseComments)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse file %s, error:%+v\", path, err)\n\t}\n\treturn pkgDefs.CollectAstFile(fileSet, packageDir, path, astFile, flag)\n}\n\n// CollectAstFile collect ast.file.\nfunc (pkgDefs *PackagesDefinitions) CollectAstFile(fileSet *token.FileSet, packageDir, path string, astFile *ast.File, flag ParseFlag) error {\n\tif pkgDefs.files == nil {\n\t\tpkgDefs.files = make(map[*ast.File]*AstFileInfo)\n\t}\n\n\tif pkgDefs.packages == nil {\n\t\tpkgDefs.packages = make(map[string]*PackageDefinitions)\n\t}\n\n\t// return without storing the file if we lack a packageDir\n\tif packageDir == \"\" {\n\t\treturn nil\n\t}\n\n\tpath, err := filepath.Abs(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdependency, ok := pkgDefs.packages[packageDir]\n\tif ok {\n\t\t// return without storing the file if it already exists\n\t\t_, exists := dependency.Files[path]\n\t\tif exists {\n\t\t\treturn nil\n\t\t}\n\n\t\tdependency.Files[path] = astFile\n\t} else {\n\t\tpkgDefs.packages[packageDir] = NewPackageDefinitions(astFile.Name.Name, packageDir).AddFile(path, astFile)\n\t}\n\n\tpkgDefs.files[astFile] = &AstFileInfo{\n\t\tFileSet:     fileSet,\n\t\tFile:        astFile,\n\t\tPath:        path,\n\t\tPackagePath: packageDir,\n\t\tParseFlag:   flag,\n\t}\n\n\treturn nil\n}\n\n// RangeFiles for range the collection of ast.File in alphabetic order.\nfunc (pkgDefs *PackagesDefinitions) RangeFiles(handle func(info *AstFileInfo) error) error {\n\tsortedFiles := make([]*AstFileInfo, 0, len(pkgDefs.files))\n\tfor _, info := range pkgDefs.files {\n\t\t// ignore package path prefix with 'vendor' or $GOROOT,\n\t\t// because the router info of api will not be included these files.\n\t\tif strings.HasPrefix(info.PackagePath, \"vendor\") || (runtime.GOROOT() != \"\" && strings.HasPrefix(info.Path, runtime.GOROOT()+string(filepath.Separator))) {\n\t\t\tcontinue\n\t\t}\n\t\tsortedFiles = append(sortedFiles, info)\n\t}\n\n\tsort.Slice(sortedFiles, func(i, j int) bool {\n\t\treturn strings.Compare(sortedFiles[i].Path, sortedFiles[j].Path) < 0\n\t})\n\n\tfor _, info := range sortedFiles {\n\t\terr := handle(info)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ParseTypes parse types\n// @Return parsed definitions.\nfunc (pkgDefs *PackagesDefinitions) ParseTypes() (map[*TypeSpecDef]*Schema, error) {\n\tparsedSchemas := make(map[*TypeSpecDef]*Schema)\n\tfor astFile, info := range pkgDefs.files {\n\t\tpkgDefs.parseTypesFromFile(astFile, info.PackagePath, parsedSchemas)\n\t\tpkgDefs.parseFunctionScopedTypesFromFile(astFile, info.PackagePath, parsedSchemas)\n\t}\n\tpkgDefs.removeAllNotUniqueTypes()\n\tpkgDefs.evaluateAllConstVariables()\n\tpkgDefs.collectConstEnums(parsedSchemas)\n\treturn parsedSchemas, nil\n}\n\nfunc (pkgDefs *PackagesDefinitions) parseTypesFromFile(astFile *ast.File, packagePath string, parsedSchemas map[*TypeSpecDef]*Schema) {\n\tfor _, astDeclaration := range astFile.Decls {\n\t\tgeneralDeclaration, ok := astDeclaration.(*ast.GenDecl)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tif generalDeclaration.Tok == token.TYPE {\n\t\t\tfor _, astSpec := range generalDeclaration.Specs {\n\t\t\t\tif typeSpec, ok := astSpec.(*ast.TypeSpec); ok {\n\t\t\t\t\ttypeSpecDef := &TypeSpecDef{\n\t\t\t\t\t\tPkgPath:  packagePath,\n\t\t\t\t\t\tFile:     astFile,\n\t\t\t\t\t\tTypeSpec: typeSpec,\n\t\t\t\t\t}\n\n\t\t\t\t\tif idt, ok := typeSpec.Type.(*ast.Ident); ok && IsGolangPrimitiveType(idt.Name) && parsedSchemas != nil {\n\t\t\t\t\t\tparsedSchemas[typeSpecDef] = &Schema{\n\t\t\t\t\t\t\tPkgPath: typeSpecDef.PkgPath,\n\t\t\t\t\t\t\tName:    astFile.Name.Name,\n\t\t\t\t\t\t\tSchema:  TransToValidPrimitiveSchema(idt.Name),\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif pkgDefs.uniqueDefinitions == nil {\n\t\t\t\t\t\tpkgDefs.uniqueDefinitions = make(map[string]*TypeSpecDef)\n\t\t\t\t\t}\n\n\t\t\t\t\tfullName := typeSpecDef.TypeName()\n\n\t\t\t\t\tanotherTypeDef, ok := pkgDefs.uniqueDefinitions[fullName]\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tif anotherTypeDef == nil {\n\t\t\t\t\t\t\ttypeSpecDef.NotUnique = true\n\t\t\t\t\t\t\tfullName = typeSpecDef.TypeName()\n\t\t\t\t\t\t\tpkgDefs.uniqueDefinitions[fullName] = typeSpecDef\n\t\t\t\t\t\t} else if typeSpecDef.PkgPath != anotherTypeDef.PkgPath {\n\t\t\t\t\t\t\tpkgDefs.uniqueDefinitions[fullName] = nil\n\t\t\t\t\t\t\tanotherTypeDef.NotUnique = true\n\t\t\t\t\t\t\tpkgDefs.uniqueDefinitions[anotherTypeDef.TypeName()] = anotherTypeDef\n\t\t\t\t\t\t\tanotherTypeDef.SetSchemaName()\n\n\t\t\t\t\t\t\ttypeSpecDef.NotUnique = true\n\t\t\t\t\t\t\tfullName = typeSpecDef.TypeName()\n\t\t\t\t\t\t\tpkgDefs.uniqueDefinitions[fullName] = typeSpecDef\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpkgDefs.uniqueDefinitions[fullName] = typeSpecDef\n\t\t\t\t\t}\n\n\t\t\t\t\ttypeSpecDef.SetSchemaName()\n\n\t\t\t\t\tif pkgDefs.packages[typeSpecDef.PkgPath] == nil {\n\t\t\t\t\t\tpkgDefs.packages[typeSpecDef.PkgPath] = NewPackageDefinitions(astFile.Name.Name, typeSpecDef.PkgPath).AddTypeSpec(typeSpecDef.Name(), typeSpecDef)\n\t\t\t\t\t} else if _, ok = pkgDefs.packages[typeSpecDef.PkgPath].TypeDefinitions[typeSpecDef.Name()]; !ok {\n\t\t\t\t\t\tpkgDefs.packages[typeSpecDef.PkgPath].AddTypeSpec(typeSpecDef.Name(), typeSpecDef)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if generalDeclaration.Tok == token.CONST {\n\t\t\t// collect consts\n\t\t\tpkgDefs.collectConstVariables(astFile, packagePath, generalDeclaration)\n\t\t}\n\t}\n}\n\nfunc (pkgDefs *PackagesDefinitions) parseFunctionScopedTypesFromFile(astFile *ast.File, packagePath string, parsedSchemas map[*TypeSpecDef]*Schema) {\n\tfor _, astDeclaration := range astFile.Decls {\n\t\tfuncDeclaration, ok := astDeclaration.(*ast.FuncDecl)\n\t\tif ok && funcDeclaration.Body != nil {\n\t\t\tfunctionScopedTypes := make(map[string]*TypeSpecDef)\n\t\t\tfor _, stmt := range funcDeclaration.Body.List {\n\t\t\t\tif declStmt, ok := (stmt).(*ast.DeclStmt); ok {\n\t\t\t\t\tif genDecl, ok := (declStmt.Decl).(*ast.GenDecl); ok && genDecl.Tok == token.TYPE {\n\t\t\t\t\t\tfor _, astSpec := range genDecl.Specs {\n\t\t\t\t\t\t\tif typeSpec, ok := astSpec.(*ast.TypeSpec); ok {\n\t\t\t\t\t\t\t\ttypeSpecDef := &TypeSpecDef{\n\t\t\t\t\t\t\t\t\tPkgPath:    packagePath,\n\t\t\t\t\t\t\t\t\tFile:       astFile,\n\t\t\t\t\t\t\t\t\tTypeSpec:   typeSpec,\n\t\t\t\t\t\t\t\t\tParentSpec: astDeclaration,\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif idt, ok := typeSpec.Type.(*ast.Ident); ok && IsGolangPrimitiveType(idt.Name) && parsedSchemas != nil {\n\t\t\t\t\t\t\t\t\tparsedSchemas[typeSpecDef] = &Schema{\n\t\t\t\t\t\t\t\t\t\tPkgPath: typeSpecDef.PkgPath,\n\t\t\t\t\t\t\t\t\t\tName:    astFile.Name.Name,\n\t\t\t\t\t\t\t\t\t\tSchema:  TransToValidPrimitiveSchema(idt.Name),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tfullName := typeSpecDef.TypeName()\n\t\t\t\t\t\t\t\tif structType, ok := typeSpecDef.TypeSpec.Type.(*ast.StructType); ok {\n\t\t\t\t\t\t\t\t\tfor _, field := range structType.Fields.List {\n\t\t\t\t\t\t\t\t\t\tvar idt *ast.Ident\n\t\t\t\t\t\t\t\t\t\tvar ok bool\n\t\t\t\t\t\t\t\t\t\tswitch field.Type.(type) {\n\t\t\t\t\t\t\t\t\t\tcase *ast.Ident:\n\t\t\t\t\t\t\t\t\t\t\tidt, ok = field.Type.(*ast.Ident)\n\t\t\t\t\t\t\t\t\t\tcase *ast.StarExpr:\n\t\t\t\t\t\t\t\t\t\t\tidt, ok = field.Type.(*ast.StarExpr).X.(*ast.Ident)\n\t\t\t\t\t\t\t\t\t\tcase *ast.ArrayType:\n\t\t\t\t\t\t\t\t\t\t\tidt, ok = field.Type.(*ast.ArrayType).Elt.(*ast.Ident)\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tif ok && !IsGolangPrimitiveType(idt.Name) {\n\t\t\t\t\t\t\t\t\t\t\tif functype, ok := functionScopedTypes[idt.Name]; ok {\n\t\t\t\t\t\t\t\t\t\t\t\tidt.Name = functype.TypeName()\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif pkgDefs.uniqueDefinitions == nil {\n\t\t\t\t\t\t\t\t\tpkgDefs.uniqueDefinitions = make(map[string]*TypeSpecDef)\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tanotherTypeDef, ok := pkgDefs.uniqueDefinitions[fullName]\n\t\t\t\t\t\t\t\tif ok {\n\t\t\t\t\t\t\t\t\tif anotherTypeDef == nil {\n\t\t\t\t\t\t\t\t\t\ttypeSpecDef.NotUnique = true\n\t\t\t\t\t\t\t\t\t\tfullName = typeSpecDef.TypeName()\n\t\t\t\t\t\t\t\t\t\tpkgDefs.uniqueDefinitions[fullName] = typeSpecDef\n\t\t\t\t\t\t\t\t\t} else if typeSpecDef.PkgPath != anotherTypeDef.PkgPath {\n\t\t\t\t\t\t\t\t\t\tpkgDefs.uniqueDefinitions[fullName] = nil\n\t\t\t\t\t\t\t\t\t\tanotherTypeDef.NotUnique = true\n\t\t\t\t\t\t\t\t\t\tpkgDefs.uniqueDefinitions[anotherTypeDef.TypeName()] = anotherTypeDef\n\t\t\t\t\t\t\t\t\t\tanotherTypeDef.SetSchemaName()\n\n\t\t\t\t\t\t\t\t\t\ttypeSpecDef.NotUnique = true\n\t\t\t\t\t\t\t\t\t\tfullName = typeSpecDef.TypeName()\n\t\t\t\t\t\t\t\t\t\tpkgDefs.uniqueDefinitions[fullName] = typeSpecDef\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tpkgDefs.uniqueDefinitions[fullName] = typeSpecDef\n\t\t\t\t\t\t\t\t\tfunctionScopedTypes[typeSpec.Name.Name] = typeSpecDef\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\ttypeSpecDef.SetSchemaName()\n\n\t\t\t\t\t\t\t\tif pkgDefs.packages[typeSpecDef.PkgPath] == nil {\n\t\t\t\t\t\t\t\t\tpkgDefs.packages[typeSpecDef.PkgPath] = NewPackageDefinitions(astFile.Name.Name, typeSpecDef.PkgPath).AddTypeSpec(fullName, typeSpecDef)\n\t\t\t\t\t\t\t\t} else if _, ok = pkgDefs.packages[typeSpecDef.PkgPath].TypeDefinitions[fullName]; !ok {\n\t\t\t\t\t\t\t\t\tpkgDefs.packages[typeSpecDef.PkgPath].AddTypeSpec(fullName, typeSpecDef)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (pkgDefs *PackagesDefinitions) collectConstVariables(astFile *ast.File, packagePath string, generalDeclaration *ast.GenDecl) {\n\tpkg, ok := pkgDefs.packages[packagePath]\n\tif !ok {\n\t\tpkg = NewPackageDefinitions(astFile.Name.Name, packagePath)\n\t\tpkgDefs.packages[packagePath] = pkg\n\t}\n\n\tvar lastValueSpec *ast.ValueSpec\n\tfor _, astSpec := range generalDeclaration.Specs {\n\t\tvalueSpec, ok := astSpec.(*ast.ValueSpec)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tif len(valueSpec.Names) == 1 && len(valueSpec.Values) == 1 {\n\t\t\tlastValueSpec = valueSpec\n\t\t} else if len(valueSpec.Names) == 1 && len(valueSpec.Values) == 0 && valueSpec.Type == nil && lastValueSpec != nil {\n\t\t\tvalueSpec.Type = lastValueSpec.Type\n\t\t\tvalueSpec.Values = lastValueSpec.Values\n\t\t}\n\t\tpkg.AddConst(astFile, valueSpec)\n\t}\n}\n\nfunc (pkgDefs *PackagesDefinitions) evaluateAllConstVariables() {\n\tfor _, pkg := range pkgDefs.packages {\n\t\tfor _, constVar := range pkg.OrderedConst {\n\t\t\tpkgDefs.EvaluateConstValue(pkg, constVar, nil)\n\t\t}\n\t}\n}\n\nfunc findFileInPackageByObject(pkg *packages.Package, obj types.Object) *ast.File {\n\treturn findFileInPackageByPos(pkg, obj.Pos())\n}\n\nfunc findFileInPackageByPos(pkg *packages.Package, pos token.Pos) *ast.File {\n\tfilename := pkg.Fset.Position(pos).Filename\n\n\tfor i, file := range pkg.CompiledGoFiles {\n\t\tif file == filename {\n\t\t\treturn pkg.Syntax[i]\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc findAstNodeInPackage(pkg *packages.Package, obj types.Object) (*ast.ValueSpec, *ast.GenDecl) {\n\tfile := findFileInPackageByObject(pkg, obj)\n\tif file == nil {\n\t\treturn nil, nil\n\t}\n\tvar found *ast.ValueSpec\n\tvar parent *ast.GenDecl\n\tast.Inspect(file, func(node ast.Node) bool {\n\t\tif found != nil || node == nil {\n\t\t\treturn false\n\t\t}\n\t\tgenDecl, ok := node.(*ast.GenDecl)\n\t\tif !ok {\n\t\t\treturn true\n\t\t}\n\t\ti := slices.IndexFunc(genDecl.Specs, func(spec ast.Spec) bool {\n\t\t\treturn spec.Pos() == obj.Pos()\n\t\t})\n\t\tif i >= 0 {\n\t\t\tfound = genDecl.Specs[i].(*ast.ValueSpec)\n\t\t\tparent = genDecl\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t})\n\treturn found, parent\n}\n\nfunc tryParseTypeFromPackage(pkg *packages.Package, constObj *types.Const) ast.Expr {\n\tspec, parent := findAstNodeInPackage(pkg, constObj)\n\tif spec == nil {\n\t\treturn nil\n\t}\n\tif spec.Type != nil {\n\t\treturn spec.Type\n\t}\n\ttypeObj := constObj.Type()\n\tfor _, otherSpec := range parent.Specs {\n\t\tif otherSpec == spec {\n\t\t\tcontinue\n\t\t}\n\t\tdeclSpec, ok := otherSpec.(*ast.ValueSpec)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tif declSpec.Type == nil {\n\t\t\tcontinue\n\t\t}\n\t\totherType := pkg.TypesInfo.TypeOf(declSpec.Names[0])\n\t\tif otherType == typeObj {\n\t\t\treturn declSpec.Type\n\t\t}\n\t}\n\treturn nil\n}\n\n// EvaluateConstValue evaluate a const variable.\nfunc (pkgDefs *PackagesDefinitions) EvaluateConstValue(pkg *PackageDefinitions, cv *ConstVariable, recursiveStack map[string]struct{}) (any, ast.Expr) {\n\tif pkg.Package != nil {\n\t\tobj := pkg.Package.Types.Scope().Lookup(cv.Name.Name)\n\t\tif obj != nil {\n\t\t\tif constObj, ok := obj.(*types.Const); ok {\n\t\t\t\tcv.Value = constant.Val(constObj.Val())\n\t\t\t\tif cv.Type == nil {\n\t\t\t\t\tcv.Type = tryParseTypeFromPackage(pkg.Package, constObj)\n\t\t\t\t}\n\t\t\t\treturn cv.Value, cv.Type\n\t\t\t}\n\t\t}\n\t}\n\tif expr, ok := cv.Value.(ast.Expr); ok {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tif fi, ok := pkgDefs.files[cv.File]; ok {\n\t\t\t\t\tpos := fi.FileSet.Position(cv.Name.NamePos)\n\t\t\t\t\tpkgDefs.debug.Printf(\"warning: failed to evaluate const %s at %s:%d:%d, %v\", cv.Name.Name, fi.Path, pos.Line, pos.Column, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t\tif recursiveStack == nil {\n\t\t\trecursiveStack = make(map[string]struct{})\n\t\t}\n\t\tfullConstName := fullTypeName(pkg.Path, cv.Name.Name)\n\t\tif _, ok = recursiveStack[fullConstName]; ok {\n\t\t\treturn nil, nil\n\t\t}\n\t\trecursiveStack[fullConstName] = struct{}{}\n\n\t\tvalue, evalType := pkg.evaluateConstValue(cv.File, cv.Name.Obj.Data.(int), expr, pkgDefs, recursiveStack)\n\t\tif cv.Type == nil && evalType != nil {\n\t\t\tcv.Type = evalType\n\t\t}\n\t\tif value != nil {\n\t\t\tcv.Value = value\n\t\t}\n\t\treturn value, cv.Type\n\t}\n\treturn cv.Value, cv.Type\n}\n\n// EvaluateConstValueByName evaluate a const variable by name.\nfunc (pkgDefs *PackagesDefinitions) EvaluateConstValueByName(file *ast.File, pkgName, constVariableName string, recursiveStack map[string]struct{}) (any, ast.Expr) {\n\tmatchedPkgPaths, externalPkgPaths := pkgDefs.findPackagePathFromImports(pkgName, file)\n\tfor _, pkgPath := range matchedPkgPaths {\n\t\tif pkg, ok := pkgDefs.packages[pkgPath]; ok {\n\t\t\tif cv, ok := pkg.ConstTable[constVariableName]; ok {\n\t\t\t\treturn pkgDefs.EvaluateConstValue(pkg, cv, recursiveStack)\n\t\t\t}\n\t\t}\n\t}\n\tif pkgDefs.parseDependency > 0 {\n\t\tfor _, pkgPath := range externalPkgPaths {\n\t\t\tif err := pkgDefs.loadExternalPackage(pkgPath); err == nil {\n\t\t\t\tif pkg, ok := pkgDefs.packages[pkgPath]; ok {\n\t\t\t\t\tif cv, ok := pkg.ConstTable[constVariableName]; ok {\n\t\t\t\t\t\treturn pkgDefs.EvaluateConstValue(pkg, cv, recursiveStack)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil, nil\n}\n\nfunc (pkgDefs *PackagesDefinitions) collectConstEnums(parsedSchemas map[*TypeSpecDef]*Schema) {\n\tfor _, pkg := range pkgDefs.packages {\n\t\tfor _, constVar := range pkg.OrderedConst {\n\t\t\tif constVar.Type == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tident *ast.Ident\n\t\t\t\tok    bool\n\t\t\t)\n\n\t\t\tswitch expr := constVar.Type.(type) {\n\t\t\tcase *ast.IndexExpr:\n\t\t\t\tident, ok = expr.X.(*ast.Ident)\n\t\t\tcase *ast.IndexListExpr:\n\t\t\t\tident, ok = expr.X.(*ast.Ident)\n\t\t\tcase *ast.Ident:\n\t\t\t\tident = expr\n\t\t\t\tok = true\n\t\t\tdefault:\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !ok || IsGolangPrimitiveType(ident.Name) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttypeDef, ok := pkg.TypeDefinitions[ident.Name]\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// delete it from parsed schemas, and will parse it again\n\t\t\tif _, ok = parsedSchemas[typeDef]; ok {\n\t\t\t\tdelete(parsedSchemas, typeDef)\n\t\t\t}\n\n\t\t\tif typeDef.Enums == nil {\n\t\t\t\ttypeDef.Enums = make([]EnumValue, 0)\n\t\t\t}\n\n\t\t\tname := constVar.VariableName()\n\t\t\tif _, ok = constVar.Value.(ast.Expr); ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tenumValue := EnumValue{\n\t\t\t\tkey:     name,\n\t\t\t\tValue:   constVar.Value,\n\t\t\t\tComment: commentWithoutNameOverride(constVar.Comment),\n\t\t\t}\n\t\t\ttypeDef.Enums = append(typeDef.Enums, enumValue)\n\t\t}\n\t}\n}\n\nfunc (pkgDefs *PackagesDefinitions) removeAllNotUniqueTypes() {\n\tfor key, ud := range pkgDefs.uniqueDefinitions {\n\t\tif ud == nil {\n\t\t\tdelete(pkgDefs.uniqueDefinitions, key)\n\t\t}\n\t}\n}\n\nfunc (pkgDefs *PackagesDefinitions) findTypeSpec(pkgPath string, typeName string) *TypeSpecDef {\n\tif pkgDefs.packages == nil {\n\t\treturn nil\n\t}\n\n\tpd, found := pkgDefs.packages[pkgPath]\n\tif found {\n\t\ttypeSpec, ok := pd.TypeDefinitions[typeName]\n\t\tif ok {\n\t\t\treturn typeSpec\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (pkgDefs *PackagesDefinitions) loadExternalPackage(importPath string) error {\n\tcwd, err := os.Getwd()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconf := loader.Config{\n\t\tParserMode: goparser.ParseComments,\n\t\tCwd:        cwd,\n\t}\n\n\tconf.Import(importPath)\n\n\tloaderProgram, err := conf.Load()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, info := range loaderProgram.AllPackages {\n\t\tpkgPath := strings.TrimPrefix(info.Pkg.Path(), \"vendor/\")\n\t\tfor _, astFile := range info.Files {\n\t\t\tpkgDefs.parseTypesFromFile(astFile, pkgPath, nil)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// findPackagePathFromImports finds out the package path of a package via ranging imports of an ast.File\n// @pkg the name of the target package\n// @file current ast.File in which to search imports\n// @return the package paths of a package of @pkg.\nfunc (pkgDefs *PackagesDefinitions) findPackagePathFromImports(pkg string, file *ast.File) (matchedPkgPaths, externalPkgPaths []string) {\n\tif file == nil {\n\t\treturn\n\t}\n\n\tif strings.ContainsRune(pkg, '.') {\n\t\tpkg = strings.Split(pkg, \".\")[0]\n\t}\n\n\tmatchLastPathPart := func(pkgPath string) bool {\n\t\tpaths := strings.Split(pkgPath, \"/\")\n\t\treturn paths[len(paths)-1] == pkg\n\t}\n\n\t// prior to match named package\n\tfor _, imp := range file.Imports {\n\t\tpath := strings.Trim(imp.Path.Value, `\"`)\n\t\tif imp.Name != nil {\n\t\t\tif imp.Name.Name == pkg {\n\t\t\t\t// if name match, break loop and return\n\t\t\t\t_, ok := pkgDefs.packages[path]\n\t\t\t\tif ok {\n\t\t\t\t\tmatchedPkgPaths = []string{path}\n\t\t\t\t\texternalPkgPaths = nil\n\t\t\t\t} else {\n\t\t\t\t\texternalPkgPaths = []string{path}\n\t\t\t\t\tmatchedPkgPaths = nil\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t} else if imp.Name.Name == \"_\" && len(pkg) > 0 {\n\t\t\t\t// for unused types\n\t\t\t\tpd, ok := pkgDefs.packages[path]\n\t\t\t\tif ok {\n\t\t\t\t\tif pd.Name == pkg {\n\t\t\t\t\t\tmatchedPkgPaths = append(matchedPkgPaths, path)\n\t\t\t\t\t}\n\t\t\t\t} else if matchLastPathPart(path) {\n\t\t\t\t\texternalPkgPaths = append(externalPkgPaths, path)\n\t\t\t\t}\n\t\t\t} else if imp.Name.Name == \".\" && len(pkg) == 0 {\n\t\t\t\t_, ok := pkgDefs.packages[path]\n\t\t\t\tif ok {\n\t\t\t\t\tmatchedPkgPaths = append(matchedPkgPaths, path)\n\t\t\t\t} else if len(pkg) == 0 || matchLastPathPart(path) {\n\t\t\t\t\texternalPkgPaths = append(externalPkgPaths, path)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if pkgDefs.packages != nil && len(pkg) > 0 {\n\t\t\tpd, ok := pkgDefs.packages[path]\n\t\t\tif ok {\n\t\t\t\tif pd.Name == pkg {\n\t\t\t\t\tmatchedPkgPaths = append(matchedPkgPaths, path)\n\t\t\t\t}\n\t\t\t} else if matchLastPathPart(path) {\n\t\t\t\texternalPkgPaths = append(externalPkgPaths, path)\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(pkg) == 0 || file.Name.Name == pkg {\n\t\tmatchedPkgPaths = append(matchedPkgPaths, pkgDefs.files[file].PackagePath)\n\t}\n\n\treturn\n}\n\nfunc (pkgDefs *PackagesDefinitions) findTypeSpecFromPackagePaths(matchedPkgPaths, externalPkgPaths []string, name string) (typeDef *TypeSpecDef) {\n\tif pkgDefs.parseDependency > 0 {\n\t\tfor _, pkgPath := range externalPkgPaths {\n\t\t\tif err := pkgDefs.loadExternalPackage(pkgPath); err == nil {\n\t\t\t\ttypeDef = pkgDefs.findTypeSpec(pkgPath, name)\n\t\t\t\tif typeDef != nil {\n\t\t\t\t\treturn typeDef\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, pkgPath := range matchedPkgPaths {\n\t\ttypeDef = pkgDefs.findTypeSpec(pkgPath, name)\n\t\tif typeDef != nil {\n\t\t\treturn typeDef\n\t\t}\n\t}\n\n\treturn typeDef\n}\n\n// FindTypeSpec finds out TypeSpecDef of a type by typeName\n// @typeName the name of the target type, if it starts with a package name, find its own package path from imports on top of @file\n// @file the ast.file in which @typeName is used\n// @pkgPath the package path of @file.\nfunc (pkgDefs *PackagesDefinitions) FindTypeSpec(typeName string, file *ast.File) *TypeSpecDef {\n\tif IsGolangPrimitiveType(typeName) {\n\t\treturn nil\n\t}\n\n\tif file == nil { // for test\n\t\treturn pkgDefs.uniqueDefinitions[typeName]\n\t}\n\n\tparts := strings.Split(strings.Split(typeName, \"[\")[0], \".\")\n\tif len(parts) > 1 {\n\t\tpkgPaths, externalPkgPaths := pkgDefs.findPackagePathFromImports(parts[0], file)\n\t\tif len(externalPkgPaths) == 0 || pkgDefs.parseDependency == ParseNone {\n\t\t\ttypeDef, ok := pkgDefs.uniqueDefinitions[typeName]\n\t\t\tif ok {\n\t\t\t\treturn typeDef\n\t\t\t}\n\t\t}\n\t\ttypeDef := pkgDefs.findTypeSpecFromPackagePaths(pkgPaths, externalPkgPaths, parts[1])\n\t\treturn pkgDefs.parametrizeGenericType(file, typeDef, typeName)\n\t}\n\n\ttypeDef, ok := pkgDefs.uniqueDefinitions[fullTypeName(file.Name.Name, typeName)]\n\tif ok {\n\t\treturn typeDef\n\t}\n\n\tname := parts[0]\n\ttypeDef, ok = pkgDefs.uniqueDefinitions[fullTypeName(file.Name.Name, name)]\n\tif !ok {\n\t\tpkgPaths, externalPkgPaths := pkgDefs.findPackagePathFromImports(\"\", file)\n\t\ttypeDef = pkgDefs.findTypeSpecFromPackagePaths(pkgPaths, externalPkgPaths, name)\n\t}\n\n\tif typeDef != nil {\n\t\treturn pkgDefs.parametrizeGenericType(file, typeDef, typeName)\n\t}\n\n\t// in case that comment //@name renamed the type with a name without a dot\n\tfor k, v := range pkgDefs.uniqueDefinitions {\n\t\tif v == nil {\n\t\t\tpkgDefs.debug.Printf(\"%s TypeSpecDef is nil\", k)\n\t\t\tcontinue\n\t\t}\n\t\tif v.SchemaName == typeName {\n\t\t\treturn v\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc findGenericTypeFromPackage(pkg *packages.Package, pos token.Pos) types.Object {\n\tfile := findFileInPackageByPos(pkg, pos)\n\tif file == nil {\n\t\treturn nil\n\t}\n\tvar found ast.Node\n\tast.Inspect(file, func(node ast.Node) bool {\n\t\tif node == nil || found != nil {\n\t\t\treturn false\n\t\t}\n\t\tif node.Pos() == pos {\n\t\t\tfound = node\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t})\n\ttypeSpec, _ := found.(*ast.TypeSpec)\n\tif typeSpec == nil {\n\t\treturn nil\n\t}\n\treturn pkg.TypesInfo.ObjectOf(typeSpec.Name)\n}\n\n// CheckTypeSpec check is there some warning or error\nfunc (pkgDefs *PackagesDefinitions) CheckTypeSpec(typeSpecDef *TypeSpecDef) {\n\tpackageDefinition := pkgDefs.packages[typeSpecDef.PkgPath]\n\tif packageDefinition == nil {\n\t\treturn\n\t}\n\tpkg := packageDefinition.Package\n\tif pkg == nil {\n\t\treturn\n\t}\n\tobj := pkg.TypesInfo.ObjectOf(typeSpecDef.TypeSpec.Name)\n\tif obj == nil {\n\t\t// generic type has modified name\n\t\tobj = findGenericTypeFromPackage(pkg, typeSpecDef.TypeSpec.Name.Pos())\n\t}\n\tif obj == nil {\n\t\tpkgDefs.debug.Printf(\"warning: %s TypeSpecDef is nil\", typeSpecDef.TypeSpec.Name.Name)\n\t\treturn\n\t}\n\tpkgDefs.checkJSONMarshal(pkg, obj)\n}\n\nfunc (pkgDefs *PackagesDefinitions) checkJSONMarshal(pkg *packages.Package, obj types.Object) {\n\tmethodSet := types.NewMethodSet(obj.Type())\n\tmethod := methodSet.Lookup(pkg.Types, \"MarshalJSON\")\n\tif method != nil {\n\t\tpkgDefs.debug.Printf(\"warning: %s.%s has MarshalJSON method, may need special handling\", pkg.PkgPath, obj.Name())\n\t}\n}\n"
  },
  {
    "path": "packages_test.go",
    "content": "package swag\n\nimport (\n\t\"go/ast\"\n\t\"go/token\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestPackagesDefinitions_ParseFile(t *testing.T) {\n\tpd := PackagesDefinitions{}\n\tpackageDir := \"github.com/swaggo/swag/testdata/simple\"\n\tassert.NoError(t, pd.ParseFile(packageDir, \"testdata/simple/main.go\", nil, ParseAll))\n\tassert.Equal(t, 1, len(pd.packages))\n\tassert.Equal(t, 1, len(pd.files))\n}\n\nfunc TestPackagesDefinitions_collectAstFile(t *testing.T) {\n\tpd := PackagesDefinitions{}\n\tfileSet := token.NewFileSet()\n\tassert.NoError(t, pd.CollectAstFile(fileSet, \"\", \"\", nil, ParseAll))\n\n\tfirstFile := &ast.File{\n\t\tName: &ast.Ident{Name: \"main.go\"},\n\t}\n\n\tpackageDir := \"github.com/swaggo/swag/testdata/simple\"\n\tassert.NoError(t, pd.CollectAstFile(fileSet, packageDir, \"testdata/simple/\"+firstFile.Name.String(), firstFile, ParseAll))\n\tassert.NotEmpty(t, pd.packages[packageDir])\n\n\tabsPath, _ := filepath.Abs(\"testdata/simple/\" + firstFile.Name.String())\n\tastFileInfo := &AstFileInfo{\n\t\tFileSet:     fileSet,\n\t\tFile:        firstFile,\n\t\tPath:        absPath,\n\t\tPackagePath: packageDir,\n\t\tParseFlag:   ParseAll,\n\t}\n\tassert.Equal(t, pd.files[firstFile], astFileInfo)\n\n\t// Override\n\tassert.NoError(t, pd.CollectAstFile(fileSet, packageDir, \"testdata/simple/\"+firstFile.Name.String(), firstFile, ParseAll))\n\tassert.Equal(t, pd.files[firstFile], astFileInfo)\n\n\t// Another file\n\tsecondFile := &ast.File{\n\t\tName: &ast.Ident{Name: \"api.go\"},\n\t}\n\tassert.NoError(t, pd.CollectAstFile(fileSet, packageDir, \"testdata/simple/\"+secondFile.Name.String(), secondFile, ParseAll))\n}\n\nfunc TestPackagesDefinitions_rangeFiles(t *testing.T) {\n\tpd := PackagesDefinitions{\n\t\tfiles: map[*ast.File]*AstFileInfo{\n\t\t\t{\n\t\t\t\tName: &ast.Ident{Name: \"main.go\"},\n\t\t\t}: {\n\t\t\t\tFile:        &ast.File{Name: &ast.Ident{Name: \"main.go\"}},\n\t\t\t\tPath:        \"testdata/simple/main.go\",\n\t\t\t\tPackagePath: \"main\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: &ast.Ident{Name: \"api.go\"},\n\t\t\t}: {\n\t\t\t\tFile:        &ast.File{Name: &ast.Ident{Name: \"api.go\"}},\n\t\t\t\tPath:        \"testdata/simple/api/api.go\",\n\t\t\t\tPackagePath: \"api\",\n\t\t\t},\n\t\t},\n\t}\n\n\ti, expect := 0, []string{\"testdata/simple/api/api.go\", \"testdata/simple/main.go\"}\n\t_ = pd.RangeFiles(func(fileInfo *AstFileInfo) error {\n\t\tassert.Equal(t, expect[i], fileInfo.Path)\n\t\ti++\n\t\treturn nil\n\t})\n}\n\nfunc TestPackagesDefinitions_ParseTypes(t *testing.T) {\n\tabsPath, _ := filepath.Abs(\"\")\n\n\tmainAST := ast.File{\n\t\tName: &ast.Ident{Name: \"main.go\"},\n\t\tDecls: []ast.Decl{\n\t\t\t&ast.GenDecl{\n\t\t\t\tTok: token.TYPE,\n\t\t\t\tSpecs: []ast.Spec{\n\t\t\t\t\t&ast.TypeSpec{\n\t\t\t\t\t\tName: &ast.Ident{Name: \"Test\"},\n\t\t\t\t\t\tType: &ast.Ident{\n\t\t\t\t\t\t\tName: \"string\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tpd := PackagesDefinitions{\n\t\tfiles: map[*ast.File]*AstFileInfo{\n\t\t\t&mainAST: {\n\t\t\t\tFile:        &mainAST,\n\t\t\t\tPath:        filepath.Join(absPath, \"testdata/simple/main.go\"),\n\t\t\t\tPackagePath: \"main\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: &ast.Ident{Name: \"api.go\"},\n\t\t\t}: {\n\t\t\t\tFile:        &ast.File{Name: &ast.Ident{Name: \"api.go\"}},\n\t\t\t\tPath:        filepath.Join(absPath, \"testdata/simple/api/api.go\"),\n\t\t\t\tPackagePath: \"api\",\n\t\t\t},\n\t\t},\n\t\tpackages: make(map[string]*PackageDefinitions),\n\t}\n\n\t_, err := pd.ParseTypes()\n\tassert.NoError(t, err)\n}\n\nfunc TestPackagesDefinitions_parseFunctionScopedTypesFromFile(t *testing.T) {\n\tmainAST := &ast.File{\n\t\tName: &ast.Ident{Name: \"main.go\"},\n\t\tDecls: []ast.Decl{\n\t\t\t&ast.FuncDecl{\n\t\t\t\tName: ast.NewIdent(\"TestFuncDecl\"),\n\t\t\t\tBody: &ast.BlockStmt{\n\t\t\t\t\tList: []ast.Stmt{\n\t\t\t\t\t\t&ast.DeclStmt{\n\t\t\t\t\t\t\tDecl: &ast.GenDecl{\n\t\t\t\t\t\t\t\tTok: token.TYPE,\n\t\t\t\t\t\t\t\tSpecs: []ast.Spec{\n\t\t\t\t\t\t\t\t\t&ast.TypeSpec{\n\t\t\t\t\t\t\t\t\t\tName: ast.NewIdent(\"response\"),\n\t\t\t\t\t\t\t\t\t\tType: ast.NewIdent(\"struct\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&ast.TypeSpec{\n\t\t\t\t\t\t\t\t\t\tName: ast.NewIdent(\"stringResponse\"),\n\t\t\t\t\t\t\t\t\t\tType: ast.NewIdent(\"string\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tpd := PackagesDefinitions{\n\t\tpackages: make(map[string]*PackageDefinitions),\n\t}\n\n\tparsedSchema := make(map[*TypeSpecDef]*Schema)\n\tpd.parseFunctionScopedTypesFromFile(mainAST, \"main\", parsedSchema)\n\n\tassert.Len(t, parsedSchema, 1)\n\n\t_, ok := pd.uniqueDefinitions[\"main.go.TestFuncDecl.response\"]\n\tassert.True(t, ok)\n\n\t_, ok = pd.packages[\"main\"].TypeDefinitions[\"main.go.TestFuncDecl.response\"]\n\tassert.True(t, ok)\n}\n\nfunc TestPackagesDefinitions_FindTypeSpec(t *testing.T) {\n\tuserDef := TypeSpecDef{\n\t\tFile: &ast.File{\n\t\t\tName: &ast.Ident{Name: \"user.go\"},\n\t\t},\n\t\tTypeSpec: &ast.TypeSpec{\n\t\t\tName: ast.NewIdent(\"User\"),\n\t\t},\n\t\tPkgPath: \"user\",\n\t}\n\tvar pkg = PackagesDefinitions{\n\t\tuniqueDefinitions: map[string]*TypeSpecDef{\n\t\t\t\"user.Model\": &userDef,\n\t\t},\n\t}\n\n\tvar nilDef *TypeSpecDef\n\tassert.Equal(t, nilDef, pkg.FindTypeSpec(\"int\", nil))\n\tassert.Equal(t, nilDef, pkg.FindTypeSpec(\"bool\", nil))\n\tassert.Equal(t, nilDef, pkg.FindTypeSpec(\"string\", nil))\n\n\tassert.Equal(t, &userDef, pkg.FindTypeSpec(\"user.Model\", nil))\n\tassert.Equal(t, nilDef, pkg.FindTypeSpec(\"Model\", nil))\n}\n\nfunc TestPackage_rangeFiles(t *testing.T) {\n\tpd := NewPackagesDefinitions()\n\tpd.files = map[*ast.File]*AstFileInfo{\n\t\t{\n\t\t\tName: &ast.Ident{Name: \"main.go\"},\n\t\t}: {\n\t\t\tFile:        &ast.File{Name: &ast.Ident{Name: \"main.go\"}},\n\t\t\tPath:        \"testdata/simple/main.go\",\n\t\t\tPackagePath: \"main\",\n\t\t},\n\t\t{\n\t\t\tName: &ast.Ident{Name: \"api.go\"},\n\t\t}: {\n\t\t\tFile:        &ast.File{Name: &ast.Ident{Name: \"api.go\"}},\n\t\t\tPath:        \"testdata/simple/api/api.go\",\n\t\t\tPackagePath: \"api\",\n\t\t},\n\t\t{\n\t\t\tName: &ast.Ident{Name: \"foo.go\"},\n\t\t}: {\n\t\t\tFile:        &ast.File{Name: &ast.Ident{Name: \"foo.go\"}},\n\t\t\tPath:        \"vendor/foo/foo.go\",\n\t\t\tPackagePath: \"vendor/foo\",\n\t\t},\n\t\t{\n\t\t\tName: &ast.Ident{Name: \"bar.go\"},\n\t\t}: {\n\t\t\tFile:        &ast.File{Name: &ast.Ident{Name: \"bar.go\"}},\n\t\t\tPath:        filepath.Join(runtime.GOROOT(), \"bar.go\"),\n\t\t\tPackagePath: \"bar\",\n\t\t},\n\t}\n\n\tvar sorted []string\n\tprocessor := func(fileInfo *AstFileInfo) error {\n\t\tsorted = append(sorted, fileInfo.Path)\n\t\treturn nil\n\t}\n\tassert.NoError(t, pd.RangeFiles(processor))\n\tassert.Equal(t, []string{\"testdata/simple/api/api.go\", \"testdata/simple/main.go\"}, sorted)\n\n\tassert.Error(t, pd.RangeFiles(func(fileInfo *AstFileInfo) error {\n\t\treturn ErrFuncTypeField\n\t}))\n\n}\n\nfunc TestPackagesDefinitions_findTypeSpec(t *testing.T) {\n\tpd := PackagesDefinitions{}\n\tvar nilTypeSpec *TypeSpecDef\n\tassert.Equal(t, nilTypeSpec, pd.findTypeSpec(\"model\", \"User\"))\n\n\tuserTypeSpec := TypeSpecDef{\n\t\tFile:     &ast.File{},\n\t\tTypeSpec: &ast.TypeSpec{},\n\t\tPkgPath:  \"model\",\n\t}\n\tpd = PackagesDefinitions{\n\t\tpackages: map[string]*PackageDefinitions{\n\t\t\t\"model\": {\n\t\t\t\tTypeDefinitions: map[string]*TypeSpecDef{\n\t\t\t\t\t\"User\": &userTypeSpec,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tassert.Equal(t, &userTypeSpec, pd.findTypeSpec(\"model\", \"User\"))\n\tassert.Equal(t, nilTypeSpec, pd.findTypeSpec(\"others\", \"User\"))\n\n}\n"
  },
  {
    "path": "parser.go",
    "content": "package swag\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"go/ast\"\n\t\"go/build\"\n\tgoparser \"go/parser\"\n\t\"go/token\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/KyleBanks/depth\"\n\t\"github.com/go-openapi/spec\"\n)\n\nconst (\n\t// CamelCase indicates using CamelCase strategy for struct field.\n\tCamelCase = \"camelcase\"\n\n\t// PascalCase indicates using PascalCase strategy for struct field.\n\tPascalCase = \"pascalcase\"\n\n\t// SnakeCase indicates using SnakeCase strategy for struct field.\n\tSnakeCase = \"snakecase\"\n\n\tidAttr                  = \"@id\"\n\tacceptAttr              = \"@accept\"\n\tproduceAttr             = \"@produce\"\n\tparamAttr               = \"@param\"\n\tsuccessAttr             = \"@success\"\n\tfailureAttr             = \"@failure\"\n\tresponseAttr            = \"@response\"\n\theaderAttr              = \"@header\"\n\ttagsAttr                = \"@tags\"\n\trouterAttr              = \"@router\"\n\tdeprecatedRouterAttr    = \"@deprecatedrouter\"\n\tsummaryAttr             = \"@summary\"\n\tdeprecatedAttr          = \"@deprecated\"\n\tsecurityAttr            = \"@security\"\n\ttitleAttr               = \"@title\"\n\tconNameAttr             = \"@contact.name\"\n\tconURLAttr              = \"@contact.url\"\n\tconEmailAttr            = \"@contact.email\"\n\tlicNameAttr             = \"@license.name\"\n\tlicURLAttr              = \"@license.url\"\n\tversionAttr             = \"@version\"\n\tdescriptionAttr         = \"@description\"\n\tdescriptionMarkdownAttr = \"@description.markdown\"\n\tsecBasicAttr            = \"@securitydefinitions.basic\"\n\tsecAPIKeyAttr           = \"@securitydefinitions.apikey\"\n\tsecApplicationAttr      = \"@securitydefinitions.oauth2.application\"\n\tsecImplicitAttr         = \"@securitydefinitions.oauth2.implicit\"\n\tsecPasswordAttr         = \"@securitydefinitions.oauth2.password\"\n\tsecAccessCodeAttr       = \"@securitydefinitions.oauth2.accesscode\"\n\ttosAttr                 = \"@termsofservice\"\n\textDocsDescAttr         = \"@externaldocs.description\"\n\textDocsURLAttr          = \"@externaldocs.url\"\n\txCodeSamplesAttr        = \"@x-codesamples\"\n\tscopeAttrPrefix         = \"@scope.\"\n\tstateAttr               = \"@state\"\n)\n\n// ParseFlag determine what to parse\ntype ParseFlag int\n\nconst (\n\t// ParseNone parse nothing\n\tParseNone ParseFlag = 0x00\n\t// ParseModels parse models\n\tParseModels = 0x01\n\t// ParseOperations parse operations\n\tParseOperations = 0x02\n\t// ParseAll parse operations and models\n\tParseAll = ParseOperations | ParseModels\n)\n\nvar (\n\t// ErrRecursiveParseStruct recursively parsing struct.\n\tErrRecursiveParseStruct = errors.New(\"recursively parsing struct\")\n\n\t// ErrFuncTypeField field type is func.\n\tErrFuncTypeField = errors.New(\"field type is func\")\n\n\t// ErrFailedConvertPrimitiveType Failed to convert for swag to interpretable type.\n\tErrFailedConvertPrimitiveType = errors.New(\"swag property: failed convert primitive type\")\n\n\t// ErrSkippedField .swaggo specifies field should be skipped.\n\tErrSkippedField = errors.New(\"field is skipped by global overrides\")\n)\n\nvar allMethod = map[string]struct{}{\n\thttp.MethodGet:     {},\n\thttp.MethodPut:     {},\n\thttp.MethodPost:    {},\n\thttp.MethodDelete:  {},\n\thttp.MethodOptions: {},\n\thttp.MethodHead:    {},\n\thttp.MethodPatch:   {},\n}\n\n// Parser implements a parser for Go source files.\ntype Parser struct {\n\t// swagger represents the root document object for the API specification\n\tswagger *spec.Swagger\n\n\t// packages store entities of APIs, definitions, file, package path etc.  and their relations\n\tpackages *PackagesDefinitions\n\n\t// parsedSchemas store schemas which have been parsed from ast.TypeSpec\n\tparsedSchemas map[*TypeSpecDef]*Schema\n\n\t// outputSchemas store schemas which will be export to swagger\n\toutputSchemas map[*TypeSpecDef]*Schema\n\n\t// PropNamingStrategy naming strategy\n\tPropNamingStrategy string\n\n\t// ParseVendor parse vendor folder\n\tParseVendor bool\n\n\t// ParseDependencies whether swag should be parse outside dependency folder: 0 none, 1 models, 2 operations, 3 all\n\tParseDependency ParseFlag\n\n\t// ParseInternal whether swag should parse internal packages\n\tParseInternal bool\n\n\t// Strict whether swag should error or warn when it detects cases which are most likely user errors\n\tStrict bool\n\n\t// RequiredByDefault set validation required for all fields by default\n\tRequiredByDefault bool\n\n\t// structStack stores full names of the structures that were already parsed or are being parsed now\n\tstructStack []*TypeSpecDef\n\n\t// markdownFileDir holds the path to the folder, where markdown files are stored\n\tmarkdownFileDir string\n\n\t// codeExampleFilesDir holds path to the folder, where code example files are stored\n\tcodeExampleFilesDir string\n\n\t// collectionFormatInQuery set the default collectionFormat otherwise then 'csv' for array in query params\n\tcollectionFormatInQuery string\n\n\t// excludes excludes dirs and files in SearchDir\n\texcludes map[string]struct{}\n\n\t// packagePrefix is a list of package path prefixes, packages that do not\n\t// match any one of them will be excluded when searching.\n\tpackagePrefix []string\n\n\t// tells parser to include only specific extension\n\tparseExtension string\n\n\t// debugging output goes here\n\tdebug Debugger\n\n\t// fieldParserFactory create FieldParser\n\tfieldParserFactory FieldParserFactory\n\n\t// Overrides allows global replacements of types. A blank replacement will be skipped.\n\tOverrides map[string]string\n\n\t// parseGoList whether swag use go list to parse dependency\n\tparseGoList bool\n\n\t// ParseGoPackages whether swag use golang.org/x/tools/go/packages to parse source.\n\t// It ignores go source files which build tags do not match.\n\t// It throws error when type check failed.\n\t// It worked better for resolve const.\n\tParseGoPackages bool\n\n\t// tags to filter the APIs after\n\ttags map[string]struct{}\n\n\t// HostState is the state of the host\n\tHostState string\n\n\t// ParseFuncBody whether swag should parse api info inside of funcs\n\tParseFuncBody bool\n\n\t// UseStructName Dont use those ugly full-path names when using dependency flag\n\tUseStructName bool\n}\n\n// FieldParserFactory create FieldParser.\ntype FieldParserFactory func(ps *Parser, field *ast.Field) FieldParser\n\n// FieldParser parse struct field.\ntype FieldParser interface {\n\tShouldSkip() bool\n\tFieldNames() ([]string, error)\n\tFirstTagValue(tag string) string\n\tFormName() string\n\tQueryName() string\n\tHeaderName() string\n\tPathName() string\n\tParamName() string\n\tCustomSchema() (*spec.Schema, error)\n\tComplementSchema(schema *spec.Schema) error\n\tIsRequired() (bool, error)\n}\n\n// Debugger is the interface that wraps the basic Printf method.\ntype Debugger interface {\n\tPrintf(format string, v ...any)\n}\n\n// New creates a new Parser with default properties.\nfunc New(options ...func(*Parser)) *Parser {\n\tparser := &Parser{\n\t\tswagger: &spec.Swagger{\n\t\t\tSwaggerProps: spec.SwaggerProps{\n\t\t\t\tInfo: &spec.Info{\n\t\t\t\t\tInfoProps: spec.InfoProps{\n\t\t\t\t\t\tContact: &spec.ContactInfo{},\n\t\t\t\t\t\tLicense: nil,\n\t\t\t\t\t},\n\t\t\t\t\tVendorExtensible: spec.VendorExtensible{\n\t\t\t\t\t\tExtensions: spec.Extensions{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tPaths: &spec.Paths{\n\t\t\t\t\tPaths: make(map[string]spec.PathItem),\n\t\t\t\t\tVendorExtensible: spec.VendorExtensible{\n\t\t\t\t\t\tExtensions: nil,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tDefinitions:         make(map[string]spec.Schema),\n\t\t\t\tSecurityDefinitions: make(map[string]*spec.SecurityScheme),\n\t\t\t},\n\t\t\tVendorExtensible: spec.VendorExtensible{\n\t\t\t\tExtensions: nil,\n\t\t\t},\n\t\t},\n\t\tpackages:           NewPackagesDefinitions(),\n\t\tdebug:              log.New(os.Stdout, \"\", log.LstdFlags),\n\t\tparsedSchemas:      make(map[*TypeSpecDef]*Schema),\n\t\toutputSchemas:      make(map[*TypeSpecDef]*Schema),\n\t\texcludes:           make(map[string]struct{}),\n\t\ttags:               make(map[string]struct{}),\n\t\tfieldParserFactory: newTagBaseFieldParser,\n\t\tOverrides:          make(map[string]string),\n\t}\n\n\tfor _, option := range options {\n\t\toption(parser)\n\t}\n\n\tparser.packages.debug = parser.debug\n\n\treturn parser\n}\n\n// SetParseDependency sets whether to parse the dependent packages.\nfunc SetParseDependency(parseDependency int) func(*Parser) {\n\treturn func(p *Parser) {\n\t\tp.ParseDependency = ParseFlag(parseDependency)\n\t\tif p.packages != nil {\n\t\t\tp.packages.parseDependency = p.ParseDependency\n\t\t}\n\t}\n}\n\n// SetUseStructName sets whether to strip the full-path definition name.\nfunc SetUseStructName(useStructName bool) func(*Parser) {\n\treturn func(p *Parser) {\n\t\tp.UseStructName = useStructName\n\t}\n}\n\n// SetMarkdownFileDirectory sets the directory to search for markdown files.\nfunc SetMarkdownFileDirectory(directoryPath string) func(*Parser) {\n\treturn func(p *Parser) {\n\t\tp.markdownFileDir = directoryPath\n\t}\n}\n\n// SetCodeExamplesDirectory sets the directory to search for code example files.\nfunc SetCodeExamplesDirectory(directoryPath string) func(*Parser) {\n\treturn func(p *Parser) {\n\t\tp.codeExampleFilesDir = directoryPath\n\t}\n}\n\n// SetExcludedDirsAndFiles sets directories and files to be excluded when searching.\nfunc SetExcludedDirsAndFiles(excludes string) func(*Parser) {\n\treturn func(p *Parser) {\n\t\tfor _, f := range strings.Split(excludes, \",\") {\n\t\t\tf = strings.TrimSpace(f)\n\t\t\tif f != \"\" {\n\t\t\t\tf = filepath.Clean(f)\n\t\t\t\tp.excludes[f] = struct{}{}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// SetPackagePrefix sets a list of package path prefixes from a comma-separated\n// string, packages that do not match any one of them will be excluded when\n// searching.\nfunc SetPackagePrefix(packagePrefix string) func(*Parser) {\n\treturn func(p *Parser) {\n\t\tfor _, f := range strings.Split(packagePrefix, \",\") {\n\t\t\tf = strings.TrimSpace(f)\n\t\t\tif f != \"\" {\n\t\t\t\tp.packagePrefix = append(p.packagePrefix, f)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// SetTags sets the tags to be included\nfunc SetTags(include string) func(*Parser) {\n\treturn func(p *Parser) {\n\t\tfor _, f := range strings.Split(include, \",\") {\n\t\t\tf = strings.TrimSpace(f)\n\t\t\tif f != \"\" {\n\t\t\t\tp.tags[f] = struct{}{}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// SetParseExtension parses only those operations which match given extension\nfunc SetParseExtension(parseExtension string) func(*Parser) {\n\treturn func(p *Parser) {\n\t\tp.parseExtension = parseExtension\n\t}\n}\n\n// SetStrict sets whether swag should error or warn when it detects cases which are most likely user errors.\nfunc SetStrict(strict bool) func(*Parser) {\n\treturn func(p *Parser) {\n\t\tp.Strict = strict\n\t}\n}\n\n// SetDebugger allows the use of user-defined implementations.\nfunc SetDebugger(logger Debugger) func(parser *Parser) {\n\treturn func(p *Parser) {\n\t\tif logger != nil {\n\t\t\tp.debug = logger\n\t\t}\n\t}\n}\n\n// SetFieldParserFactory allows the use of user-defined implementations.\nfunc SetFieldParserFactory(factory FieldParserFactory) func(parser *Parser) {\n\treturn func(p *Parser) {\n\t\tp.fieldParserFactory = factory\n\t}\n}\n\n// SetOverrides allows the use of user-defined global type overrides.\nfunc SetOverrides(overrides map[string]string) func(parser *Parser) {\n\treturn func(p *Parser) {\n\t\tfor k, v := range overrides {\n\t\t\tp.Overrides[k] = v\n\t\t}\n\t}\n}\n\n// SetCollectionFormat set default collection format\nfunc SetCollectionFormat(collectionFormat string) func(*Parser) {\n\treturn func(p *Parser) {\n\t\tp.collectionFormatInQuery = collectionFormat\n\t}\n}\n\n// ParseUsingGoList sets whether swag use go list to parse dependency\nfunc ParseUsingGoList(enabled bool) func(parser *Parser) {\n\treturn func(p *Parser) {\n\t\tp.parseGoList = enabled\n\t}\n}\n\n// ParseAPI parses general api info for given searchDir and mainAPIFile.\nfunc (parser *Parser) ParseAPI(searchDir string, mainAPIFile string, parseDepth int) error {\n\treturn parser.ParseAPIMultiSearchDir([]string{searchDir}, mainAPIFile, parseDepth)\n}\n\n// skipPackageByPrefix returns true the given pkgpath does not match\n// any user-defined package path prefixes.\nfunc (parser *Parser) skipPackageByPrefix(pkgpath string) bool {\n\tif len(parser.packagePrefix) == 0 {\n\t\treturn false\n\t}\n\tfor _, prefix := range parser.packagePrefix {\n\t\tif strings.HasPrefix(pkgpath, prefix) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// ParseAPIMultiSearchDir is like ParseAPI but for multiple search dirs.\nfunc (parser *Parser) ParseAPIMultiSearchDir(searchDirs []string, mainAPIFile string, parseDepth int) error {\n\tabsMainAPIFilePath, err := filepath.Abs(filepath.Join(searchDirs[0], mainAPIFile))\n\tif err != nil {\n\t\treturn err\n\t}\n\tif parser.ParseGoPackages {\n\t\tif err := parser.loadPackagesAndDeps(searchDirs, absMainAPIFilePath); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tfor _, searchDir := range searchDirs {\n\t\t\tparser.debug.Printf(\"Generate general API Info, search dir:%s\", searchDir)\n\n\t\t\tpackageDir, err := getPkgName(searchDir)\n\t\t\tif err != nil {\n\t\t\t\tparser.debug.Printf(\"warning: failed to get package name in dir: %s, error: %s\", searchDir, err.Error())\n\t\t\t}\n\n\t\t\terr = parser.getAllGoFileInfo(packageDir, searchDir)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\t// Use 'go list' command instead of depth.Resolve()\n\tif parser.ParseDependency > 0 && !parser.ParseGoPackages {\n\t\tallDir := append([]string{filepath.Dir(absMainAPIFilePath)}, searchDirs...)\n\t\tif parser.parseGoList {\n\t\t\tpkgs, err := listPackages(context.Background(), allDir, nil, \"-deps\")\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tlength := len(pkgs)\n\t\t\tfor i := 0; i < length; i++ {\n\t\t\t\terr := parser.getAllGoFileInfoFromDepsByList(pkgs[i], parser.ParseDependency)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tdirImported := make(map[string]struct{}) // for deduplication\n\t\t\tfor _, dir := range allDir {             // ignore search dir (have been parsed)\n\t\t\t\tabsDir, err := filepath.Abs(dir)\n\t\t\t\tif err == nil {\n\t\t\t\t\tdirImported[absDir] = struct{}{}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor index, dir := range allDir {\n\t\t\t\tvar t depth.Tree\n\t\t\t\tt.ResolveInternal = true\n\t\t\t\tt.MaxDepth = parseDepth\n\n\t\t\t\tpkgName, err := getPkgName(dir)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif index == 0 { // ignore error when load search dir\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\terr = t.Resolve(pkgName)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"pkg %s cannot find all dependencies, %s\", pkgName, err)\n\t\t\t\t}\n\t\t\t\tfor i := 0; i < len(t.Root.Deps); i++ {\n\t\t\t\t\terr := parser.getAllGoFileInfoFromDeps(&t.Root.Deps[i], parser.ParseDependency, dirImported)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\terr = parser.ParseGeneralAPIInfo(absMainAPIFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparser.parsedSchemas, err = parser.packages.ParseTypes()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = parser.packages.RangeFiles(parser.ParseRouterAPIInfo)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn parser.checkOperationIDUniqueness()\n}\n\nfunc getPkgName(searchDir string) (string, error) {\n\tcmd := exec.Command(\"go\", \"list\", \"-f={{.ImportPath}}\")\n\tcmd.Dir = searchDir\n\n\tvar stdout, stderr strings.Builder\n\n\tcmd.Stdout = &stdout\n\tcmd.Stderr = &stderr\n\n\tif err := cmd.Run(); err != nil {\n\t\treturn \"\", fmt.Errorf(\"execute go list command, %s, stdout:%s, stderr:%s\", err, stdout.String(), stderr.String())\n\t}\n\n\toutStr, _ := stdout.String(), stderr.String()\n\n\tif outStr[0] == '_' { // will shown like _/{GOPATH}/src/{YOUR_PACKAGE} when NOT enable GO MODULE.\n\t\toutStr = strings.TrimPrefix(outStr, \"_\"+build.Default.GOPATH+\"/src/\")\n\t}\n\n\tf := strings.Split(outStr, \"\\n\")\n\n\toutStr = f[0]\n\n\treturn outStr, nil\n}\n\n// ParseGeneralAPIInfo parses general api info for given mainAPIFile path.\nfunc (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {\n\tfileTree, err := goparser.ParseFile(token.NewFileSet(), mainAPIFile, nil, goparser.ParseComments)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot parse source files %s: %s\", mainAPIFile, err)\n\t}\n\n\tparser.swagger.Swagger = \"2.0\"\n\n\tfor _, comment := range fileTree.Comments {\n\t\tcomments := strings.Split(comment.Text(), \"\\n\")\n\t\tif !isGeneralAPIComment(comments) {\n\t\t\tcontinue\n\t\t}\n\n\t\terr = parseGeneralAPIInfo(parser, comments)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc parseGeneralAPIInfo(parser *Parser, comments []string) error {\n\tpreviousAttribute := \"\"\n\tvar tag *spec.Tag\n\t// parsing classic meta data model\n\tfor line := 0; line < len(comments); line++ {\n\t\tcommentLine := comments[line]\n\t\tcommentLine = strings.TrimSpace(commentLine)\n\t\tif len(commentLine) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tfields := FieldsByAnySpace(commentLine, 2)\n\n\t\tattribute := fields[0]\n\t\tvar value string\n\t\tif len(fields) > 1 {\n\t\t\tvalue = fields[1]\n\t\t}\n\n\t\tswitch attr := strings.ToLower(attribute); attr {\n\t\tcase versionAttr, titleAttr, tosAttr, licNameAttr, licURLAttr, conNameAttr, conURLAttr, conEmailAttr:\n\t\t\tsetSwaggerInfo(parser.swagger, attr, value)\n\t\tcase descriptionAttr:\n\t\t\tif previousAttribute == attribute {\n\t\t\t\tparser.swagger.Info.Description = AppendDescription(parser.swagger.Info.Description, value)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tsetSwaggerInfo(parser.swagger, attr, value)\n\t\tcase descriptionMarkdownAttr:\n\t\t\tcommentInfo, err := getMarkdownForTag(\"api\", parser.markdownFileDir)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tsetSwaggerInfo(parser.swagger, descriptionAttr, string(commentInfo))\n\n\t\tcase \"@host\":\n\t\t\tparser.swagger.Host = value\n\t\tcase \"@hoststate\":\n\t\t\tfields = FieldsByAnySpace(commentLine, 3)\n\t\t\tif len(fields) != 3 {\n\t\t\t\treturn fmt.Errorf(\"%s needs 3 arguments\", attribute)\n\t\t\t}\n\t\t\tif parser.HostState == fields[1] {\n\t\t\t\tparser.swagger.Host = fields[2]\n\t\t\t}\n\t\tcase \"@basepath\":\n\t\t\tparser.swagger.BasePath = value\n\n\t\tcase acceptAttr:\n\t\t\terr := parser.ParseAcceptComment(value)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase produceAttr:\n\t\t\terr := parser.ParseProduceComment(value)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase \"@schemes\":\n\t\t\tparser.swagger.Schemes = strings.Split(value, \" \")\n\t\tcase \"@tag.name\":\n\t\t\tif parser.matchTag(value) {\n\t\t\t\tparser.swagger.Tags = append(parser.swagger.Tags, spec.Tag{\n\t\t\t\t\tTagProps: spec.TagProps{\n\t\t\t\t\t\tName: value,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\ttag = &parser.swagger.Tags[len(parser.swagger.Tags)-1]\n\t\t\t} else {\n\t\t\t\ttag = nil\n\t\t\t}\n\t\tcase \"@tag.description\":\n\t\t\tif tag != nil {\n\t\t\t\ttag.TagProps.Description = value\n\t\t\t}\n\t\tcase \"@tag.description.markdown\":\n\t\t\tif tag != nil {\n\t\t\t\tcommentInfo, err := getMarkdownForTag(tag.TagProps.Name, parser.markdownFileDir)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\ttag.TagProps.Description = string(commentInfo)\n\t\t\t}\n\t\tcase \"@tag.docs.url\":\n\t\t\tif tag != nil {\n\t\t\t\ttag.TagProps.ExternalDocs = &spec.ExternalDocumentation{\n\t\t\t\t\tURL: value,\n\t\t\t\t}\n\t\t\t}\n\t\tcase \"@tag.docs.description\":\n\t\t\tif tag != nil {\n\t\t\t\tif tag.TagProps.ExternalDocs == nil {\n\t\t\t\t\treturn fmt.Errorf(\"%s needs to come after a @tags.docs.url\", attribute)\n\t\t\t\t}\n\n\t\t\t\ttag.TagProps.ExternalDocs.Description = value\n\t\t\t}\n\t\tcase secBasicAttr, secAPIKeyAttr, secApplicationAttr, secImplicitAttr, secPasswordAttr, secAccessCodeAttr:\n\t\t\tscheme, err := parseSecAttributes(attribute, comments, &line)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tparser.swagger.SecurityDefinitions[value] = scheme\n\n\t\tcase securityAttr:\n\t\t\tparser.swagger.Security = append(parser.swagger.Security, parseSecurity(value))\n\n\t\tcase \"@query.collection.format\":\n\t\t\tparser.collectionFormatInQuery = TransToValidCollectionFormat(value)\n\n\t\tcase extDocsDescAttr, extDocsURLAttr:\n\t\t\tif parser.swagger.ExternalDocs == nil {\n\t\t\t\tparser.swagger.ExternalDocs = new(spec.ExternalDocumentation)\n\t\t\t}\n\t\t\tswitch attr {\n\t\t\tcase extDocsDescAttr:\n\t\t\t\tparser.swagger.ExternalDocs.Description = value\n\t\t\tcase extDocsURLAttr:\n\t\t\t\tparser.swagger.ExternalDocs.URL = value\n\t\t\t}\n\n\t\tdefault:\n\t\t\tif strings.HasPrefix(attribute, \"@x-\") {\n\t\t\t\textensionName := attribute[1:]\n\n\t\t\t\textExistsInSecurityDef := false\n\t\t\t\t// for each security definition\n\t\t\t\tfor _, v := range parser.swagger.SecurityDefinitions {\n\t\t\t\t\t// check if extension exists\n\t\t\t\t\t_, extExistsInSecurityDef = v.VendorExtensible.Extensions.GetString(extensionName)\n\t\t\t\t\t// if it exists in at least one, then we stop iterating\n\t\t\t\t\tif extExistsInSecurityDef {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if it is present on security def, don't add it again\n\t\t\t\tif extExistsInSecurityDef {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif len(value) == 0 {\n\t\t\t\t\treturn fmt.Errorf(\"annotation %s need a value\", attribute)\n\t\t\t\t}\n\n\t\t\t\tvar valueJSON any\n\t\t\t\terr := json.Unmarshal([]byte(value), &valueJSON)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"annotation %s need a valid json value\", attribute)\n\t\t\t\t}\n\n\t\t\t\tif strings.Contains(extensionName, \"logo\") {\n\t\t\t\t\tparser.swagger.Info.Extensions.Add(extensionName, valueJSON)\n\t\t\t\t} else {\n\t\t\t\t\tif parser.swagger.Extensions == nil {\n\t\t\t\t\t\tparser.swagger.Extensions = make(map[string]any)\n\t\t\t\t\t}\n\n\t\t\t\t\tparser.swagger.Extensions[attribute[1:]] = valueJSON\n\t\t\t\t}\n\t\t\t} else if strings.HasPrefix(attribute, \"@tag.x-\") {\n\t\t\t\textensionName := attribute[5:]\n\n\t\t\t\tif len(value) == 0 {\n\t\t\t\t\treturn fmt.Errorf(\"annotation %s need a value\", attribute)\n\t\t\t\t}\n\n\t\t\t\tif tag.Extensions == nil {\n\t\t\t\t\ttag.Extensions = make(map[string]any)\n\t\t\t\t}\n\n\t\t\t\t// tag.Extensions.Add(extensionName, value) works wrong (transforms extensionName to lower case)\n\t\t\t\t// needed to save case for ReDoc\n\t\t\t\t// https://redocly.com/docs/api-reference-docs/specification-extensions/x-display-name/\n\t\t\t\ttag.Extensions[extensionName] = value\n\t\t\t}\n\t\t}\n\n\t\tpreviousAttribute = attribute\n\t}\n\n\treturn nil\n}\n\nfunc setSwaggerInfo(swagger *spec.Swagger, attribute, value string) {\n\tswitch attribute {\n\tcase versionAttr:\n\t\tswagger.Info.Version = value\n\tcase titleAttr:\n\t\tswagger.Info.Title = value\n\tcase tosAttr:\n\t\tswagger.Info.TermsOfService = value\n\tcase descriptionAttr:\n\t\tswagger.Info.Description = value\n\tcase conNameAttr:\n\t\tswagger.Info.Contact.Name = value\n\tcase conEmailAttr:\n\t\tswagger.Info.Contact.Email = value\n\tcase conURLAttr:\n\t\tswagger.Info.Contact.URL = value\n\tcase licNameAttr:\n\t\tswagger.Info.License = initIfEmpty(swagger.Info.License)\n\t\tswagger.Info.License.Name = value\n\tcase licURLAttr:\n\t\tswagger.Info.License = initIfEmpty(swagger.Info.License)\n\t\tswagger.Info.License.URL = value\n\t}\n}\n\nfunc parseSecAttributes(context string, lines []string, index *int) (*spec.SecurityScheme, error) {\n\tconst (\n\t\tin               = \"@in\"\n\t\tname             = \"@name\"\n\t\tdescriptionAttr  = \"@description\"\n\t\ttokenURL         = \"@tokenurl\"\n\t\tauthorizationURL = \"@authorizationurl\"\n\t)\n\n\tvar search []string\n\n\tattribute := strings.ToLower(FieldsByAnySpace(lines[*index], 2)[0])\n\tswitch attribute {\n\tcase secBasicAttr:\n\t\treturn spec.BasicAuth(), nil\n\tcase secAPIKeyAttr:\n\t\tsearch = []string{in, name}\n\tcase secApplicationAttr, secPasswordAttr:\n\t\tsearch = []string{tokenURL}\n\tcase secImplicitAttr:\n\t\tsearch = []string{authorizationURL}\n\tcase secAccessCodeAttr:\n\t\tsearch = []string{tokenURL, authorizationURL}\n\t}\n\n\t// For the first line we get the attributes in the context parameter, so we skip to the next one\n\t*index++\n\n\tattrMap, scopes := make(map[string]string), make(map[string]string)\n\textensions, description := make(map[string]any), \"\"\n\nloopline:\n\tfor ; *index < len(lines); *index++ {\n\t\tv := strings.TrimSpace(lines[*index])\n\t\tif len(v) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfields := FieldsByAnySpace(v, 2)\n\t\tsecurityAttr := strings.ToLower(fields[0])\n\t\tvar value string\n\t\tif len(fields) > 1 {\n\t\t\tvalue = fields[1]\n\t\t}\n\n\t\tfor _, findterm := range search {\n\t\t\tif securityAttr == findterm {\n\t\t\t\tattrMap[securityAttr] = value\n\t\t\t\tcontinue loopline\n\t\t\t}\n\t\t}\n\n\t\tif isExists, err := isExistsScope(securityAttr); err != nil {\n\t\t\treturn nil, err\n\t\t} else if isExists {\n\t\t\tscopes[securityAttr[len(scopeAttrPrefix):]] = value\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.HasPrefix(securityAttr, \"@x-\") {\n\t\t\t// Add the custom attribute without the @\n\t\t\textensions[securityAttr[1:]] = value\n\t\t\tcontinue\n\t\t}\n\n\t\t// Not mandatory field\n\t\tif securityAttr == descriptionAttr {\n\t\t\tif description != \"\" {\n\t\t\t\tdescription += \"\\n\"\n\t\t\t}\n\t\t\tdescription += value\n\t\t}\n\n\t\t// next securityDefinitions\n\t\tif strings.Index(securityAttr, \"@securitydefinitions.\") == 0 {\n\t\t\t// Go back to the previous line and break\n\t\t\t*index--\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif len(attrMap) != len(search) {\n\t\treturn nil, fmt.Errorf(\"%s is %v required\", context, search)\n\t}\n\n\tvar scheme *spec.SecurityScheme\n\n\tswitch attribute {\n\tcase secAPIKeyAttr:\n\t\tscheme = spec.APIKeyAuth(attrMap[name], attrMap[in])\n\tcase secApplicationAttr:\n\t\tscheme = spec.OAuth2Application(attrMap[tokenURL])\n\tcase secImplicitAttr:\n\t\tscheme = spec.OAuth2Implicit(attrMap[authorizationURL])\n\tcase secPasswordAttr:\n\t\tscheme = spec.OAuth2Password(attrMap[tokenURL])\n\tcase secAccessCodeAttr:\n\t\tscheme = spec.OAuth2AccessToken(attrMap[authorizationURL], attrMap[tokenURL])\n\t}\n\n\tscheme.Description = description\n\n\tfor extKey, extValue := range extensions {\n\t\tscheme.AddExtension(extKey, extValue)\n\t}\n\n\tfor scope, scopeDescription := range scopes {\n\t\tscheme.AddScope(scope, scopeDescription)\n\t}\n\n\treturn scheme, nil\n}\n\nfunc parseSecurity(commentLine string) map[string][]string {\n\tsecurityMap := make(map[string][]string)\n\n\tfor _, securityOption := range securityPairSepPattern.Split(commentLine, -1) {\n\t\tsecurityOption = strings.TrimSpace(securityOption)\n\n\t\tleft, right := strings.Index(securityOption, \"[\"), strings.Index(securityOption, \"]\")\n\n\t\tif !(left == -1 && right == -1) {\n\t\t\tscopes := securityOption[left+1 : right]\n\n\t\t\tvar options []string\n\n\t\t\tfor _, scope := range strings.Split(scopes, \",\") {\n\t\t\t\toptions = append(options, strings.TrimSpace(scope))\n\t\t\t}\n\n\t\t\tsecurityKey := securityOption[0:left]\n\t\t\tsecurityMap[securityKey] = append(securityMap[securityKey], options...)\n\t\t} else {\n\t\t\tsecurityKey := strings.TrimSpace(securityOption)\n\t\t\tsecurityMap[securityKey] = []string{}\n\t\t}\n\t}\n\n\treturn securityMap\n}\n\nfunc initIfEmpty(license *spec.License) *spec.License {\n\tif license == nil {\n\t\treturn new(spec.License)\n\t}\n\n\treturn license\n}\n\n// ParseAcceptComment parses comment for given `accept` comment string.\nfunc (parser *Parser) ParseAcceptComment(commentLine string) error {\n\treturn parseMimeTypeList(commentLine, &parser.swagger.Consumes, \"%v accept type can't be accepted\")\n}\n\n// ParseProduceComment parses comment for given `produce` comment string.\nfunc (parser *Parser) ParseProduceComment(commentLine string) error {\n\treturn parseMimeTypeList(commentLine, &parser.swagger.Produces, \"%v produce type can't be accepted\")\n}\n\nfunc isGeneralAPIComment(comments []string) bool {\n\tfor _, commentLine := range comments {\n\t\tcommentLine = strings.TrimSpace(commentLine)\n\t\tif len(commentLine) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tattribute := strings.ToLower(FieldsByAnySpace(commentLine, 2)[0])\n\t\tswitch attribute {\n\t\t// The @summary, @router, @success, @failure annotation belongs to Operation\n\t\tcase summaryAttr, routerAttr, successAttr, failureAttr, responseAttr:\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc getMarkdownForTag(tagName string, dirPath string) ([]byte, error) {\n\tif tagName == \"\" {\n\t\t// this happens when parsing the @description.markdown attribute\n\t\t// it will be called properly another time with tagName=\"api\"\n\t\t// so we can safely return an empty byte slice here\n\t\treturn make([]byte, 0), nil\n\t}\n\n\tdirEntries, err := os.ReadDir(dirPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, entry := range dirEntries {\n\t\tif entry.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tfileName := entry.Name()\n\n\t\texpectedFileName := tagName\n\t\tif !strings.HasSuffix(tagName, \".md\") {\n\t\t\texpectedFileName = tagName + \".md\"\n\t\t}\n\n\t\tif fileName == expectedFileName {\n\t\t\tfullPath := filepath.Join(dirPath, fileName)\n\n\t\t\tcommentInfo, err := os.ReadFile(fullPath)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"Failed to read markdown file %s error: %s \", fullPath, err)\n\t\t\t}\n\n\t\t\treturn commentInfo, nil\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"Unable to find markdown file for tag %s in the given directory\", tagName)\n}\n\nfunc isExistsScope(scope string) (bool, error) {\n\ts := strings.Fields(scope)\n\tfor _, v := range s {\n\t\tif strings.HasPrefix(v, scopeAttrPrefix) {\n\t\t\tif strings.Contains(v, \",\") {\n\t\t\t\treturn false, fmt.Errorf(\"@scope can't use comma(,) get=%s\", v)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn strings.HasPrefix(scope, scopeAttrPrefix), nil\n}\n\nfunc getTagsFromComment(comment string) (tags []string) {\n\tcommentLine := strings.TrimSpace(strings.TrimLeft(comment, \"/\"))\n\tif len(commentLine) == 0 {\n\t\treturn nil\n\t}\n\n\tattribute := strings.Fields(commentLine)[0]\n\tlineRemainder, lowerAttribute := strings.TrimSpace(commentLine[len(attribute):]), strings.ToLower(attribute)\n\n\tif lowerAttribute == tagsAttr {\n\t\tfor _, tag := range strings.Split(lineRemainder, \",\") {\n\t\t\ttags = append(tags, strings.TrimSpace(tag))\n\t\t}\n\t}\n\treturn\n\n}\n\nfunc (parser *Parser) matchTag(tag string) bool {\n\tif len(parser.tags) == 0 {\n\t\treturn true\n\t}\n\n\tif _, has := parser.tags[\"!\"+tag]; has {\n\t\treturn false\n\t}\n\tif _, has := parser.tags[tag]; has {\n\t\treturn true\n\t}\n\n\t// If all tags are negation then we should return true\n\tfor key := range parser.tags {\n\t\tif key[0] != '!' {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (parser *Parser) matchTags(comments []*ast.Comment) (match bool) {\n\tif len(parser.tags) == 0 {\n\t\treturn true\n\t}\n\n\tmatch = false\n\tfor _, comment := range comments {\n\t\tfor _, tag := range getTagsFromComment(comment.Text) {\n\t\t\tif _, has := parser.tags[\"!\"+tag]; has {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif _, has := parser.tags[tag]; has {\n\t\t\t\tmatch = true // keep iterating as it may contain a tag that is excluded\n\t\t\t}\n\t\t}\n\t}\n\n\tif !match {\n\t\t// If all tags are negation then we should return true\n\t\tfor key := range parser.tags {\n\t\t\tif key[0] != '!' {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\nfunc matchExtension(extensionToMatch string, comments []*ast.Comment) (match bool) {\n\tif len(extensionToMatch) != 0 {\n\t\tfor _, comment := range comments {\n\t\t\tcommentLine := strings.TrimSpace(strings.TrimLeft(comment.Text, \"/\"))\n\t\t\tfields := FieldsByAnySpace(commentLine, 2)\n\t\t\tif len(fields) > 0 {\n\t\t\t\tlowerAttribute := strings.ToLower(fields[0])\n\n\t\t\t\tif lowerAttribute == fmt.Sprintf(\"@x-%s\", strings.ToLower(extensionToMatch)) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc getFuncDoc(decl any) (*ast.CommentGroup, bool) {\n\tswitch astDecl := decl.(type) {\n\tcase *ast.FuncDecl: // func name() {}\n\t\treturn astDecl.Doc, true\n\tcase *ast.GenDecl: // var name = namePointToFuncDirectlyOrIndirectly\n\t\tif astDecl.Tok != token.VAR {\n\t\t\treturn nil, false\n\t\t}\n\t\tif len(astDecl.Specs) == 0 {\n\t\t\treturn nil, false\n\t\t}\n\t\tvarSpec, ok := astDecl.Specs[0].(*ast.ValueSpec)\n\t\tif !ok || len(varSpec.Values) != 1 {\n\t\t\treturn nil, false\n\t\t}\n\t\t_, ok = getFuncDoc(varSpec)\n\t\treturn astDecl.Doc, ok\n\tcase *ast.ValueSpec:\n\t\tif len(astDecl.Values) == 0 {\n\t\t\treturn nil, false\n\t\t}\n\t\tvalue, ok := astDecl.Values[0].(*ast.Ident)\n\t\tif !ok || value == nil || value.Obj == nil || value.Obj.Decl == nil {\n\t\t\treturn nil, false\n\t\t}\n\t\t_, ok = getFuncDoc(value.Obj.Decl)\n\t\treturn astDecl.Doc, ok\n\t}\n\treturn nil, false\n}\n\n// ParseRouterAPIInfo parses router api info for given astFile.\nfunc (parser *Parser) ParseRouterAPIInfo(fileInfo *AstFileInfo) error {\n\tif (fileInfo.ParseFlag & ParseOperations) == ParseNone {\n\t\treturn nil\n\t}\n\n\t// parse File.Comments instead of File.Decls.Doc if ParseFuncBody flag set to \"true\"\n\tif parser.ParseFuncBody {\n\t\tfor _, astComments := range fileInfo.File.Comments {\n\t\t\tif astComments.List != nil {\n\t\t\t\tif err := parser.parseRouterAPIInfoComment(astComments.List, fileInfo); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tfor _, decl := range fileInfo.File.Decls {\n\t\tfuncDoc, ok := getFuncDoc(decl)\n\t\tif ok && funcDoc != nil && funcDoc.List != nil {\n\t\t\tif err := parser.parseRouterAPIInfoComment(funcDoc.List, fileInfo); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (parser *Parser) parseRouterAPIInfoComment(comments []*ast.Comment, fileInfo *AstFileInfo) error {\n\tif parser.matchTags(comments) && matchExtension(parser.parseExtension, comments) {\n\t\t// for per 'function' comment, create a new 'Operation' object\n\t\toperation := NewOperation(parser, SetCodeExampleFilesDirectory(parser.codeExampleFilesDir))\n\t\tfor _, comment := range comments {\n\t\t\terr := operation.ParseComment(comment.Text, fileInfo.File)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"ParseComment error in file %s for comment: '%s': %+v\", fileInfo.Path, comment.Text, err)\n\t\t\t}\n\t\t\tif operation.State != \"\" && operation.State != parser.HostState {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\terr := processRouterOperation(parser, operation)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc refRouteMethodOp(item *spec.PathItem, method string) (op **spec.Operation) {\n\tswitch method {\n\tcase http.MethodGet:\n\t\top = &item.Get\n\tcase http.MethodPost:\n\t\top = &item.Post\n\tcase http.MethodDelete:\n\t\top = &item.Delete\n\tcase http.MethodPut:\n\t\top = &item.Put\n\tcase http.MethodPatch:\n\t\top = &item.Patch\n\tcase http.MethodHead:\n\t\top = &item.Head\n\tcase http.MethodOptions:\n\t\top = &item.Options\n\t}\n\n\treturn\n}\n\nfunc processRouterOperation(parser *Parser, operation *Operation) error {\n\tfor _, routeProperties := range operation.RouterProperties {\n\t\tvar (\n\t\t\tpathItem spec.PathItem\n\t\t\tok       bool\n\t\t)\n\n\t\tpathItem, ok = parser.swagger.Paths.Paths[routeProperties.Path]\n\t\tif !ok {\n\t\t\tpathItem = spec.PathItem{}\n\t\t}\n\n\t\top := refRouteMethodOp(&pathItem, routeProperties.HTTPMethod)\n\n\t\t// check if we already have an operation for this path and method\n\t\tif *op != nil {\n\t\t\terr := fmt.Errorf(\"route %s %s is declared multiple times\", routeProperties.HTTPMethod, routeProperties.Path)\n\t\t\tif parser.Strict {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tparser.debug.Printf(\"warning: %s\\n\", err)\n\t\t}\n\n\t\tif len(operation.RouterProperties) > 1 {\n\t\t\tnewOp := *operation\n\t\t\tvar validParams []spec.Parameter\n\t\t\tfor _, param := range newOp.Operation.OperationProps.Parameters {\n\t\t\t\tif param.In == \"path\" && !strings.Contains(routeProperties.Path, param.Name) {\n\t\t\t\t\t// This path param is not actually contained in the path, skip adding it to the final params\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tvalidParams = append(validParams, param)\n\t\t\t}\n\t\t\tnewOp.Operation.OperationProps.Parameters = validParams\n\t\t\t*op = &newOp.Operation\n\t\t} else {\n\t\t\t*op = &operation.Operation\n\t\t}\n\n\t\tif routeProperties.Deprecated {\n\t\t\t(*op).Deprecated = routeProperties.Deprecated\n\t\t}\n\n\t\tparser.swagger.Paths.Paths[routeProperties.Path] = pathItem\n\t}\n\n\treturn nil\n}\n\nfunc convertFromSpecificToPrimitive(typeName string) (string, error) {\n\tname := typeName\n\tif strings.ContainsRune(name, '.') {\n\t\tname = strings.Split(name, \".\")[1]\n\t}\n\n\tswitch strings.ToUpper(name) {\n\tcase \"TIME\", \"OBJECTID\", \"UUID\":\n\t\treturn STRING, nil\n\tcase \"DECIMAL\":\n\t\treturn NUMBER, nil\n\t}\n\n\treturn typeName, ErrFailedConvertPrimitiveType\n}\n\nfunc (parser *Parser) getTypeSchema(typeName string, file *ast.File, ref bool) (*spec.Schema, error) {\n\tif override, ok := parser.Overrides[typeName]; ok {\n\t\tparser.debug.Printf(\"Override detected for %s: using %s instead\", typeName, override)\n\t\treturn parseObjectSchema(parser, override, file)\n\t}\n\n\tif IsInterfaceLike(typeName) {\n\t\treturn &spec.Schema{}, nil\n\t}\n\tif IsGolangPrimitiveType(typeName) {\n\t\treturn TransToValidPrimitiveSchema(typeName), nil\n\t}\n\n\tschemaType, err := convertFromSpecificToPrimitive(typeName)\n\tif err == nil {\n\t\treturn PrimitiveSchema(schemaType), nil\n\t}\n\n\ttypeSpecDef := parser.packages.FindTypeSpec(typeName, file)\n\tif typeSpecDef == nil {\n\t\treturn nil, fmt.Errorf(\"cannot find type definition: %s\", typeName)\n\t}\n\n\tif override, ok := parser.Overrides[typeSpecDef.FullPath()]; ok {\n\t\tif override == \"\" {\n\t\t\tparser.debug.Printf(\"Override detected for %s: ignoring\", typeSpecDef.FullPath())\n\n\t\t\treturn nil, ErrSkippedField\n\t\t}\n\n\t\tparser.debug.Printf(\"Override detected for %s: using %s instead\", typeSpecDef.FullPath(), override)\n\n\t\tseparator := strings.LastIndex(override, \".\")\n\t\tif separator == -1 {\n\t\t\t// treat as a swaggertype tag\n\t\t\tparts := strings.Split(override, \",\")\n\n\t\t\treturn BuildCustomSchema(parts)\n\t\t}\n\n\t\ttypeSpecDef = parser.packages.findTypeSpec(override[0:separator], override[separator+1:])\n\t}\n\n\tparser.packages.CheckTypeSpec(typeSpecDef)\n\n\tschema, ok := parser.parsedSchemas[typeSpecDef]\n\tif !ok {\n\t\tvar err error\n\n\t\tschema, err = parser.ParseDefinition(typeSpecDef)\n\t\tif err != nil {\n\t\t\tif err == ErrRecursiveParseStruct && ref {\n\t\t\t\treturn parser.getRefTypeSchema(typeSpecDef, schema), nil\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"%s: %w\", typeName, err)\n\t\t}\n\t}\n\n\tif ref {\n\t\tif IsComplexSchema(schema.Schema) {\n\t\t\treturn parser.getRefTypeSchema(typeSpecDef, schema), nil\n\t\t}\n\t\t// if it is a simple schema, just return a copy\n\t\tnewSchema := *schema.Schema\n\t\treturn &newSchema, nil\n\t}\n\n\treturn schema.Schema, nil\n}\n\nfunc (parser *Parser) getRefTypeSchema(typeSpecDef *TypeSpecDef, schema *Schema) *spec.Schema {\n\t_, ok := parser.outputSchemas[typeSpecDef]\n\tif !ok {\n\t\tparser.swagger.Definitions[schema.Name] = spec.Schema{}\n\n\t\tif schema.Schema != nil {\n\t\t\tparser.swagger.Definitions[schema.Name] = *schema.Schema\n\t\t}\n\n\t\tparser.outputSchemas[typeSpecDef] = schema\n\t}\n\n\trefSchema := RefSchema(schema.Name)\n\n\treturn refSchema\n}\n\nfunc (parser *Parser) isInStructStack(typeSpecDef *TypeSpecDef) bool {\n\tfor _, specDef := range parser.structStack {\n\t\tif typeSpecDef == specDef {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// ParseDefinition parses given type spec that corresponds to the type under\n// given name and package, and populates swagger schema definitions registry\n// with a schema for the given type\nfunc (parser *Parser) ParseDefinition(typeSpecDef *TypeSpecDef) (*Schema, error) {\n\ttypeName := typeSpecDef.TypeName()\n\tschema, found := parser.parsedSchemas[typeSpecDef]\n\tif found {\n\t\tparser.debug.Printf(\"Skipping '%s', already parsed.\", typeName)\n\n\t\treturn schema, nil\n\t}\n\n\tif parser.isInStructStack(typeSpecDef) {\n\t\tparser.debug.Printf(\"Skipping '%s', recursion detected.\", typeName)\n\n\t\t// Ensure SchemaName is set before using it\n\t\ttypeSpecDef.SetSchemaName()\n\t\tschemaName := typeName\n\t\tif typeSpecDef.SchemaName != \"\" {\n\t\t\tschemaName = typeSpecDef.SchemaName\n\t\t}\n\n\t\treturn &Schema{\n\t\t\t\tName:    schemaName,\n\t\t\t\tPkgPath: typeSpecDef.PkgPath,\n\t\t\t\tSchema:  PrimitiveSchema(OBJECT),\n\t\t\t},\n\t\t\tErrRecursiveParseStruct\n\t}\n\n\tif parser.UseStructName {\n\t\tschemaName := strings.Split(typeSpecDef.SchemaName, \".\")\n\t\tif len(schemaName) > 1 {\n\t\t\ttypeSpecDef.SchemaName = schemaName[len(schemaName)-1]\n\t\t\ttypeName = typeSpecDef.SchemaName\n\t\t} else {\n\t\t\tparser.debug.Printf(\"Could not strip type name of %s\", typeName)\n\t\t}\n\t}\n\n\tparser.structStack = append(parser.structStack, typeSpecDef)\n\n\tparser.debug.Printf(\"Generating %s\", typeName)\n\n\tdefinition, err := parser.parseTypeExpr(typeSpecDef.File, typeSpecDef.TypeSpec.Type, false)\n\tif err != nil {\n\t\tparser.debug.Printf(\"Error parsing type definition '%s': %s\", typeName, err)\n\t\treturn nil, err\n\t}\n\n\tif definition.Description == \"\" {\n\t\terr = parser.fillDefinitionDescription(definition, typeSpecDef.File, typeSpecDef)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif len(typeSpecDef.Enums) > 0 {\n\t\tvar varnames []string\n\t\tvar enumComments = make(map[string]string)\n\t\tvar enumDescriptions = make([]string, 0, len(typeSpecDef.Enums))\n\t\tfor _, value := range typeSpecDef.Enums {\n\t\t\tdefinition.Enum = append(definition.Enum, value.Value)\n\t\t\tvarnames = append(varnames, value.key)\n\t\t\tenumDescriptions = append(enumDescriptions, value.Comment)\n\t\t\tif len(value.Comment) > 0 {\n\t\t\t\tenumComments[value.key] = value.Comment\n\t\t\t}\n\t\t}\n\t\tif definition.Extensions == nil {\n\t\t\tdefinition.Extensions = make(spec.Extensions)\n\t\t}\n\t\tdefinition.Extensions[enumVarNamesExtension] = varnames\n\t\tif len(enumComments) > 0 {\n\t\t\tdefinition.Extensions[enumCommentsExtension] = enumComments\n\t\t\tdefinition.Extensions[enumDescriptionsExtension] = enumDescriptions\n\t\t}\n\t}\n\n\tschemaName := typeName\n\n\tif typeSpecDef.SchemaName != \"\" {\n\t\tschemaName = typeSpecDef.SchemaName\n\t}\n\n\tsch := Schema{\n\t\tName:    schemaName,\n\t\tPkgPath: typeSpecDef.PkgPath,\n\t\tSchema:  definition,\n\t}\n\tparser.parsedSchemas[typeSpecDef] = &sch\n\n\t// update an empty schema as a result of recursion\n\ts2, found := parser.outputSchemas[typeSpecDef]\n\tif found {\n\t\tparser.swagger.Definitions[s2.Name] = *definition\n\t}\n\n\treturn &sch, nil\n}\n\nfunc fullTypeName(parts ...string) string {\n\treturn strings.Join(parts, \".\")\n}\n\n// fillDefinitionDescription additionally fills fields in definition (spec.Schema)\n// TODO: If .go file contains many types, it may work for a long time\nfunc (parser *Parser) fillDefinitionDescription(definition *spec.Schema, file *ast.File, typeSpecDef *TypeSpecDef) (err error) {\n\tif file == nil {\n\t\treturn\n\t}\n\tfor _, astDeclaration := range file.Decls {\n\t\tgeneralDeclaration, ok := astDeclaration.(*ast.GenDecl)\n\t\tif !ok || generalDeclaration.Tok != token.TYPE {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, astSpec := range generalDeclaration.Specs {\n\t\t\ttypeSpec, ok := astSpec.(*ast.TypeSpec)\n\t\t\tif !ok || typeSpec != typeSpecDef.TypeSpec {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvar typeName string\n\t\t\tif typeSpec.Name != nil {\n\t\t\t\ttypeName = typeSpec.Name.Name\n\t\t\t}\n\t\t\tdefinition.Description, err =\n\t\t\t\tparser.extractDeclarationDescription(typeName, typeSpec.Doc, typeSpec.Comment, generalDeclaration.Doc)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// extractDeclarationDescription gets first description\n// from attribute descriptionAttr in commentGroups (ast.CommentGroup)\nfunc (parser *Parser) extractDeclarationDescription(typeName string, commentGroups ...*ast.CommentGroup) (string, error) {\n\tvar description string\n\n\tfor _, commentGroup := range commentGroups {\n\t\tif commentGroup == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tisHandlingDescription := false\n\n\t\tfor _, comment := range commentGroup.List {\n\t\t\tcommentText := strings.TrimSpace(strings.TrimLeft(comment.Text, \"/\"))\n\t\t\tif len(commentText) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfields := FieldsByAnySpace(commentText, 2)\n\t\t\tattribute := fields[0]\n\n\t\t\tif attr := strings.ToLower(attribute); attr == descriptionMarkdownAttr {\n\t\t\t\tif len(fields) > 1 {\n\t\t\t\t\ttypeName = fields[1]\n\t\t\t\t}\n\t\t\t\tif typeName == \"\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tdesc, err := getMarkdownForTag(typeName, parser.markdownFileDir)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\t\t\t\t// if found markdown description, we will only use the markdown file content\n\t\t\t\treturn string(desc), nil\n\t\t\t} else if attr != descriptionAttr {\n\t\t\t\tif !isHandlingDescription {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tisHandlingDescription = true\n\t\t\tdescription += \" \" + strings.TrimSpace(commentText[len(attribute):])\n\t\t}\n\t}\n\n\treturn strings.TrimLeft(description, \" \"), nil\n}\n\n// parseTypeExpr parses given type expression that corresponds to the type under\n// given name and package, and returns swagger schema for it.\nfunc (parser *Parser) parseTypeExpr(file *ast.File, typeExpr ast.Expr, ref bool) (*spec.Schema, error) {\n\tswitch expr := typeExpr.(type) {\n\t// type Foo interface{}\n\tcase *ast.InterfaceType:\n\t\treturn &spec.Schema{}, nil\n\n\t// type Foo struct {...}\n\tcase *ast.StructType:\n\t\treturn parser.parseStruct(file, expr.Fields)\n\n\t// type Foo Baz\n\tcase *ast.Ident:\n\t\treturn parser.getTypeSchema(expr.Name, file, ref)\n\n\t// type Foo *Baz\n\tcase *ast.StarExpr:\n\t\treturn parser.parseTypeExpr(file, expr.X, ref)\n\n\t// type Foo pkg.Bar\n\tcase *ast.SelectorExpr:\n\t\tif xIdent, ok := expr.X.(*ast.Ident); ok {\n\t\t\treturn parser.getTypeSchema(fullTypeName(xIdent.Name, expr.Sel.Name), file, ref)\n\t\t}\n\t// type Foo []Baz\n\tcase *ast.ArrayType:\n\t\titemSchema, err := parser.parseTypeExpr(file, expr.Elt, true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn spec.ArrayProperty(itemSchema), nil\n\t// type Foo map[string]Bar\n\tcase *ast.MapType:\n\t\tif _, ok := expr.Value.(*ast.InterfaceType); ok {\n\t\t\treturn spec.MapProperty(nil), nil\n\t\t}\n\t\tschema, err := parser.parseTypeExpr(file, expr.Value, true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn spec.MapProperty(schema), nil\n\n\tcase *ast.FuncType:\n\t\treturn nil, ErrFuncTypeField\n\t\t// ...\n\t}\n\n\treturn parser.parseGenericTypeExpr(file, typeExpr)\n}\n\nfunc (parser *Parser) parseStruct(file *ast.File, fields *ast.FieldList) (*spec.Schema, error) {\n\trequired, properties := make([]string, 0), make(map[string]spec.Schema)\n\n\tfor _, field := range fields.List {\n\t\tfieldProps, requiredFromAnon, err := parser.parseStructField(file, field)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, ErrFuncTypeField) || errors.Is(err, ErrSkippedField) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif len(fieldProps) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\trequired = append(required, requiredFromAnon...)\n\n\t\tfor k, v := range fieldProps {\n\t\t\tproperties[k] = v\n\t\t}\n\t}\n\n\tsort.Strings(required)\n\n\treturn &spec.Schema{\n\t\tSchemaProps: spec.SchemaProps{\n\t\t\tType:       []string{OBJECT},\n\t\t\tProperties: properties,\n\t\t\tRequired:   required,\n\t\t},\n\t}, nil\n}\n\nfunc (parser *Parser) parseStructField(file *ast.File, field *ast.Field) (map[string]spec.Schema, []string, error) {\n\tif field.Tag != nil {\n\t\tskip, ok := reflect.StructTag(strings.ReplaceAll(field.Tag.Value, \"`\", \"\")).Lookup(\"swaggerignore\")\n\t\tif ok && strings.EqualFold(skip, \"true\") {\n\t\t\treturn nil, nil, nil\n\t\t}\n\t}\n\n\tps := parser.fieldParserFactory(parser, field)\n\n\tif ps.ShouldSkip() {\n\t\treturn nil, nil, nil\n\t}\n\n\tfieldNames, err := ps.FieldNames()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif len(fieldNames) == 0 {\n\t\ttypeName, err := getFieldType(file, field.Type, nil)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tschema, err := parser.getTypeSchema(typeName, file, false)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tif len(schema.Type) > 0 && schema.Type[0] == OBJECT {\n\t\t\tif len(schema.Properties) == 0 {\n\t\t\t\treturn nil, nil, nil\n\t\t\t}\n\n\t\t\tproperties := map[string]spec.Schema{}\n\t\t\tfor k, v := range schema.Properties {\n\t\t\t\tproperties[k] = v\n\t\t\t}\n\n\t\t\treturn properties, schema.SchemaProps.Required, nil\n\t\t}\n\t\t// for alias type of non-struct types ,such as array,map, etc. ignore field tag.\n\t\treturn map[string]spec.Schema{typeName: *schema}, nil, nil\n\n\t}\n\n\tschema, err := ps.CustomSchema()\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"%v: %w\", fieldNames, err)\n\t}\n\n\tif schema == nil {\n\t\ttypeName, err := getFieldType(file, field.Type, nil)\n\t\tif err == nil {\n\t\t\t// named type\n\t\t\tschema, err = parser.getTypeSchema(typeName, file, true)\n\t\t} else {\n\t\t\t// unnamed type\n\t\t\tschema, err = parser.parseTypeExpr(file, field.Type, false)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"%v: %w\", fieldNames, err)\n\t\t}\n\t}\n\n\terr = ps.ComplementSchema(schema)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"%v: %w\", fieldNames, err)\n\t}\n\n\tvar tagRequired []string\n\n\trequired, err := ps.IsRequired()\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"%v: %w\", fieldNames, err)\n\t}\n\n\tif required {\n\t\ttagRequired = append(tagRequired, fieldNames...)\n\t}\n\n\tif formName := ps.FormName(); len(formName) > 0 {\n\t\tschema.AddExtension(\"formData\", formName)\n\t}\n\tif queryName := ps.QueryName(); len(queryName) > 0 {\n\t\tschema.AddExtension(\"query\", queryName)\n\t}\n\tif headerName := ps.HeaderName(); len(headerName) > 0 {\n\t\tschema.AddExtension(\"header\", headerName)\n\t}\n\tif pathName := ps.PathName(); len(pathName) > 0 {\n\t\tschema.AddExtension(\"path\", pathName)\n\t} else if paramName := ps.ParamName(); len(paramName) > 0 {\n\t\tschema.AddExtension(\"path\", paramName)\n\t}\n\tif len(schema.Type) > 0 && schema.Type[0] == ARRAY {\n\t\tif collectionFormat := ps.FirstTagValue(collectionFormatTag); len(collectionFormat) > 0 {\n\t\t\tschema.AddExtension(collectionFormatTag, collectionFormat)\n\t\t}\n\t}\n\tfields := make(map[string]spec.Schema)\n\tfor _, name := range fieldNames {\n\t\tfields[name] = *schema\n\t}\n\treturn fields, tagRequired, nil\n}\n\nfunc getFieldType(file *ast.File, field ast.Expr, genericParamTypeDefs map[string]*genericTypeSpec) (string, error) {\n\tswitch fieldType := field.(type) {\n\tcase *ast.Ident:\n\t\treturn fieldType.Name, nil\n\tcase *ast.SelectorExpr:\n\t\tpackageName, err := getFieldType(file, fieldType.X, genericParamTypeDefs)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\treturn fullTypeName(packageName, fieldType.Sel.Name), nil\n\tcase *ast.StarExpr:\n\t\tfullName, err := getFieldType(file, fieldType.X, genericParamTypeDefs)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\treturn fullName, nil\n\tdefault:\n\t\treturn getGenericFieldType(file, field, genericParamTypeDefs)\n\t}\n}\n\nfunc (parser *Parser) getUnderlyingSchema(schema *spec.Schema) *spec.Schema {\n\tif schema == nil {\n\t\treturn nil\n\t}\n\n\tif url := schema.Ref.GetURL(); url != nil {\n\t\tif pos := strings.LastIndexByte(url.Fragment, '/'); pos >= 0 {\n\t\t\tname := url.Fragment[pos+1:]\n\t\t\tif schema, ok := parser.swagger.Definitions[name]; ok {\n\t\t\t\treturn &schema\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(schema.AllOf) > 0 {\n\t\tmerged := &spec.Schema{}\n\t\tMergeSchema(merged, schema)\n\t\tfor _, s := range schema.AllOf {\n\t\t\tMergeSchema(merged, parser.getUnderlyingSchema(&s))\n\t\t}\n\t\treturn merged\n\t}\n\treturn nil\n}\n\n// GetSchemaTypePath get path of schema type.\nfunc (parser *Parser) GetSchemaTypePath(schema *spec.Schema, depth int) []string {\n\tif schema == nil || depth == 0 {\n\t\treturn nil\n\t}\n\n\tif underlying := parser.getUnderlyingSchema(schema); underlying != nil {\n\t\treturn parser.GetSchemaTypePath(underlying, depth)\n\t}\n\n\tif len(schema.Type) > 0 {\n\t\tswitch schema.Type[0] {\n\t\tcase ARRAY:\n\t\t\tdepth--\n\n\t\t\ts := []string{schema.Type[0]}\n\n\t\t\treturn append(s, parser.GetSchemaTypePath(schema.Items.Schema, depth)...)\n\t\tcase OBJECT:\n\t\t\tif schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {\n\t\t\t\t// for map\n\t\t\t\tdepth--\n\n\t\t\t\ts := []string{schema.Type[0]}\n\n\t\t\t\treturn append(s, parser.GetSchemaTypePath(schema.AdditionalProperties.Schema, depth)...)\n\t\t\t}\n\t\t}\n\n\t\treturn []string{schema.Type[0]}\n\t}\n\n\treturn []string{ANY}\n}\n\n// defineTypeOfExample example value define the type (object and array unsupported).\nfunc defineTypeOfExample(schemaType, arrayType, exampleValue string) (interface{}, error) {\n\tswitch schemaType {\n\tcase STRING:\n\t\treturn exampleValue, nil\n\tcase NUMBER:\n\t\tv, err := strconv.ParseFloat(exampleValue, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"example value %s can't convert to %s err: %s\", exampleValue, schemaType, err)\n\t\t}\n\n\t\treturn v, nil\n\tcase INTEGER:\n\t\tv, err := strconv.Atoi(exampleValue)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"example value %s can't convert to %s err: %s\", exampleValue, schemaType, err)\n\t\t}\n\n\t\treturn v, nil\n\tcase BOOLEAN:\n\t\tv, err := strconv.ParseBool(exampleValue)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"example value %s can't convert to %s err: %s\", exampleValue, schemaType, err)\n\t\t}\n\n\t\treturn v, nil\n\tcase ARRAY:\n\t\tvalues := strings.Split(exampleValue, \",\")\n\t\tresult := make([]any, 0)\n\t\tfor _, value := range values {\n\t\t\tv, err := defineTypeOfExample(arrayType, \"\", value)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tresult = append(result, v)\n\t\t}\n\n\t\treturn result, nil\n\tcase OBJECT:\n\t\tif arrayType == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"%s is unsupported type in example value `%s`\", schemaType, exampleValue)\n\t\t}\n\n\t\tvalues := strings.Split(exampleValue, \",\")\n\n\t\tresult := map[string]any{}\n\n\t\tfor _, value := range values {\n\t\t\tmapData := strings.SplitN(value, \":\", 2)\n\n\t\t\tif len(mapData) == 2 {\n\t\t\t\tv, err := defineTypeOfExample(arrayType, \"\", mapData[1])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\tresult[mapData[0]] = v\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"example value %s should format: key:value\", exampleValue)\n\t\t}\n\n\t\treturn result, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"%s is unsupported type in example value %s\", schemaType, exampleValue)\n}\n\n// GetAllGoFileInfo gets all Go source files information for given searchDir.\nfunc (parser *Parser) getAllGoFileInfo(packageDir, searchDir string) error {\n\tif parser.skipPackageByPrefix(packageDir) {\n\t\treturn nil // ignored by user-defined package path prefixes\n\t}\n\treturn filepath.Walk(searchDir, func(path string, f os.FileInfo, wError error) error {\n\t\tif wError != nil {\n\t\t\treturn fmt.Errorf(\"failed to access path %q, err: %v\\n\", path, wError)\n\t\t}\n\t\terr := parser.Skip(path, f)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif f.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\trelPath, err := filepath.Rel(searchDir, path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn parser.parseFile(filepath.ToSlash(filepath.Dir(filepath.Clean(filepath.Join(packageDir, relPath)))), path, nil, ParseAll)\n\t})\n}\n\nfunc (parser *Parser) getAllGoFileInfoFromDeps(pkg *depth.Pkg, parseFlag ParseFlag, dirImported map[string]struct{}) error {\n\tignoreInternal := pkg.Internal && !parser.ParseInternal\n\tif ignoreInternal || !pkg.Resolved { // ignored internal and not resolved dependencies\n\t\treturn nil\n\t}\n\n\tif pkg.Raw != nil && parser.skipPackageByPrefix(pkg.Raw.ImportPath) {\n\t\treturn nil // ignored by user-defined package path prefixes\n\t}\n\n\t// Skip cgo\n\tif pkg.Raw == nil && pkg.Name == \"C\" {\n\t\treturn nil\n\t}\n\n\tsrcDir := pkg.Raw.Dir\n\tif _, ok := dirImported[srcDir]; ok {\n\t\treturn nil\n\t}\n\tdirImported[srcDir] = struct{}{}\n\n\tfiles, err := os.ReadDir(srcDir) // only parsing files in the dir(don't contain sub dir files)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, f := range files {\n\t\tif f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tpath := filepath.Join(srcDir, f.Name())\n\t\tif err := parser.parseFile(pkg.Name, path, nil, parseFlag); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor i := 0; i < len(pkg.Deps); i++ {\n\t\tif err := parser.getAllGoFileInfoFromDeps(&pkg.Deps[i], parseFlag, dirImported); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (parser *Parser) parseFile(packageDir, path string, src any, flag ParseFlag) error {\n\tif strings.HasSuffix(strings.ToLower(path), \"_test.go\") || filepath.Ext(path) != \".go\" {\n\t\treturn nil\n\t}\n\n\treturn parser.packages.ParseFile(packageDir, path, src, flag)\n}\n\nfunc (parser *Parser) checkOperationIDUniqueness() error {\n\t// operationsIds contains all operationId annotations to check it's unique\n\toperationsIds := make(map[string]string)\n\n\tfor path, item := range parser.swagger.Paths.Paths {\n\t\tvar method, id string\n\n\t\tfor method = range allMethod {\n\t\t\top := refRouteMethodOp(&item, method)\n\t\t\tif *op != nil {\n\t\t\t\tid = (**op).ID\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif id == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tcurrent := fmt.Sprintf(\"%s %s\", method, path)\n\n\t\tprevious, ok := operationsIds[id]\n\t\tif ok {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"duplicated @id annotation '%s' found in '%s', previously declared in: '%s'\",\n\t\t\t\tid, current, previous)\n\t\t}\n\n\t\toperationsIds[id] = current\n\t}\n\n\treturn nil\n}\n\n// Skip returns filepath.SkipDir error if match vendor and hidden folder.\nfunc (parser *Parser) Skip(path string, f os.FileInfo) error {\n\treturn walkWith(parser.excludes, parser.ParseVendor)(path, f)\n}\n\nfunc walkWith(excludes map[string]struct{}, parseVendor bool) func(path string, fileInfo os.FileInfo) error {\n\treturn func(path string, f os.FileInfo) error {\n\t\tif f.IsDir() {\n\t\t\tif !parseVendor && f.Name() == \"vendor\" || // ignore \"vendor\"\n\t\t\t\tf.Name() == \"docs\" || // exclude docs\n\t\t\t\tlen(f.Name()) > 1 && f.Name()[0] == '.' && f.Name() != \"..\" { // exclude all hidden folder\n\t\t\t\treturn filepath.SkipDir\n\t\t\t}\n\n\t\t\tif excludes != nil {\n\t\t\t\tif _, ok := excludes[path]; ok {\n\t\t\t\t\treturn filepath.SkipDir\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\n// GetSwagger returns *spec.Swagger which is the root document object for the API specification.\nfunc (parser *Parser) GetSwagger() *spec.Swagger {\n\treturn parser.swagger\n}\n\n// addTestType just for tests.\nfunc (parser *Parser) addTestType(typename string) {\n\ttypeDef := &TypeSpecDef{}\n\tparser.packages.uniqueDefinitions[typename] = typeDef\n\tparser.parsedSchemas[typeDef] = &Schema{\n\t\tPkgPath: \"\",\n\t\tName:    typename,\n\t\tSchema:  PrimitiveSchema(OBJECT),\n\t}\n}\n"
  },
  {
    "path": "parser_test.go",
    "content": "package swag\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"go/ast\"\n\tgoparser \"go/parser\"\n\t\"go/token\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/go-openapi/spec\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst defaultParseDepth = 100\n\nconst mainAPIFile = \"main.go\"\n\nfunc TestNew(t *testing.T) {\n\tt.Run(\"SetMarkdownFileDirectory\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texpected := \"docs/markdown\"\n\t\tp := New(SetMarkdownFileDirectory(expected))\n\t\tassert.Equal(t, expected, p.markdownFileDir)\n\t})\n\n\tt.Run(\"SetCodeExamplesDirectory\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texpected := \"docs/examples\"\n\t\tp := New(SetCodeExamplesDirectory(expected))\n\t\tassert.Equal(t, expected, p.codeExampleFilesDir)\n\t})\n\n\tt.Run(\"SetStrict\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tp := New()\n\t\tassert.Equal(t, false, p.Strict)\n\n\t\tp = New(SetStrict(true))\n\t\tassert.Equal(t, true, p.Strict)\n\t})\n\n\tt.Run(\"SetDebugger\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tlogger := log.New(&bytes.Buffer{}, \"\", log.LstdFlags)\n\n\t\tp := New(SetDebugger(logger))\n\t\tassert.Equal(t, logger, p.debug)\n\t})\n\n\tt.Run(\"SetFieldParserFactory\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tp := New(SetFieldParserFactory(nil))\n\t\tassert.Nil(t, p.fieldParserFactory)\n\t})\n}\n\nfunc TestSetOverrides(t *testing.T) {\n\tt.Parallel()\n\n\toverrides := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\n\tp := New(SetOverrides(overrides))\n\tassert.Equal(t, overrides, p.Overrides)\n}\n\nfunc TestOverrides_getTypeSchema(t *testing.T) {\n\tt.Parallel()\n\n\toverrides := map[string]string{\n\t\t\"sql.NullString\": \"string\",\n\t}\n\n\tp := New(SetOverrides(overrides))\n\n\tt.Run(\"Override sql.NullString by string\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ts, err := p.getTypeSchema(\"sql.NullString\", nil, false)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Truef(t, s.Type.Contains(\"string\"), \"type sql.NullString should be overridden by string\")\n\t\t}\n\t})\n\n\tt.Run(\"Missing Override for sql.NullInt64\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t_, err := p.getTypeSchema(\"sql.NullInt64\", nil, false)\n\t\tif assert.Error(t, err) {\n\t\t\tassert.Equal(t, \"cannot find type definition: sql.NullInt64\", err.Error())\n\t\t}\n\t})\n}\n\nfunc TestParser_ParseDefinition(t *testing.T) {\n\tp := New()\n\n\t// Parsing existing type\n\tdefinition := &TypeSpecDef{\n\t\tPkgPath: \"github.com/swagger/swag\",\n\t\tFile: &ast.File{\n\t\t\tName: &ast.Ident{\n\t\t\t\tName: \"swag\",\n\t\t\t},\n\t\t},\n\t\tTypeSpec: &ast.TypeSpec{\n\t\t\tName: &ast.Ident{\n\t\t\t\tName: \"Test\",\n\t\t\t},\n\t\t},\n\t}\n\n\texpected := &Schema{}\n\tp.parsedSchemas[definition] = expected\n\n\tschema, err := p.ParseDefinition(definition)\n\tassert.NoError(t, err)\n\tassert.Equal(t, expected, schema)\n\n\t// Parsing *ast.FuncType\n\tdefinition = &TypeSpecDef{\n\t\tPkgPath: \"github.com/swagger/swag/model\",\n\t\tFile: &ast.File{\n\t\t\tName: &ast.Ident{\n\t\t\t\tName: \"model\",\n\t\t\t},\n\t\t},\n\t\tTypeSpec: &ast.TypeSpec{\n\t\t\tName: &ast.Ident{\n\t\t\t\tName: \"Test\",\n\t\t\t},\n\t\t\tType: &ast.FuncType{},\n\t\t},\n\t}\n\t_, err = p.ParseDefinition(definition)\n\tassert.Error(t, err)\n\n\t// Parsing *ast.FuncType with parent spec\n\tdefinition = &TypeSpecDef{\n\t\tPkgPath: \"github.com/swagger/swag/model\",\n\t\tFile: &ast.File{\n\t\t\tName: &ast.Ident{\n\t\t\t\tName: \"model\",\n\t\t\t},\n\t\t},\n\t\tTypeSpec: &ast.TypeSpec{\n\t\t\tName: &ast.Ident{\n\t\t\t\tName: \"Test\",\n\t\t\t},\n\t\t\tType: &ast.FuncType{},\n\t\t},\n\t\tParentSpec: &ast.FuncDecl{\n\t\t\tName: ast.NewIdent(\"TestFuncDecl\"),\n\t\t},\n\t}\n\t_, err = p.ParseDefinition(definition)\n\tassert.Error(t, err)\n\tassert.Equal(t, \"model.TestFuncDecl.Test\", definition.TypeName())\n}\n\nfunc TestParser_ParseGeneralApiInfo(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\n    \"schemes\": [\n        \"http\",\n        \"https\"\n    ],\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\\nIt has a lot of beautiful features.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\",\n        \"x-logo\": {\n            \"altText\": \"Petstore logo\",\n            \"backgroundColor\": \"#FFFFFF\",\n            \"url\": \"https://redocly.github.io/redoc/petstore-logo.png\"\n        }\n    },\n    \"host\": \"petstore.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {},\n    \"securityDefinitions\": {\n        \"ApiKeyAuth\": {\n            \"description\": \"some description\",\n            \"type\": \"apiKey\",\n            \"name\": \"Authorization\",\n            \"in\": \"header\"\n        },\n        \"BasicAuth\": {\n            \"type\": \"basic\"\n        },\n        \"OAuth2AccessCode\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"accessCode\",\n            \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\"\n            },\n            \"x-tokenname\": \"id_token\"\n        },\n        \"OAuth2Application\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"application\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"write\": \"Grants write access\"\n            }\n        },\n        \"OAuth2Implicit\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"implicit\",\n            \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"write\": \"Grants write access\"\n            },\n            \"x-google-audiences\": \"some_audience.google.com\"\n        },\n        \"OAuth2Password\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"password\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"read\": \"Grants read access\",\n                \"write\": \"Grants write access\"\n            }\n        }\n    },\n    \"externalDocs\": {\n        \"description\": \"OpenAPI\",\n        \"url\": \"https://swagger.io/resources/open-api\"\n    },\n    \"x-google-endpoints\": [\n        {\n            \"allowCors\": true,\n            \"name\": \"name.endpoints.environment.cloud.goog\"\n        }\n    ],\n    \"x-google-marks\": \"marks values\"\n}`\n\tgopath := os.Getenv(\"GOPATH\")\n\tassert.NotNil(t, gopath)\n\n\tp := New()\n\n\terr := p.ParseGeneralAPIInfo(\"testdata/main.go\")\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParser_ParseGeneralApiInfoTemplated(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        }\n    },\n    \"paths\": {},\n    \"securityDefinitions\": {\n        \"ApiKeyAuth\": {\n            \"type\": \"apiKey\",\n            \"name\": \"Authorization\",\n            \"in\": \"header\"\n        },\n        \"BasicAuth\": {\n            \"type\": \"basic\"\n        },\n        \"OAuth2AccessCode\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"accessCode\",\n            \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\"\n            }\n        },\n        \"OAuth2Application\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"application\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"write\": \"Grants write access\"\n            }\n        },\n        \"OAuth2Implicit\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"implicit\",\n            \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"write\": \"Grants write access\"\n            }\n        },\n        \"OAuth2Password\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"password\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"read\": \"Grants read access\",\n                \"write\": \"Grants write access\"\n            }\n        }\n    },\n    \"externalDocs\": {\n        \"description\": \"OpenAPI\",\n        \"url\": \"https://swagger.io/resources/open-api\"\n    },\n    \"x-google-endpoints\": [\n        {\n            \"allowCors\": true,\n            \"name\": \"name.endpoints.environment.cloud.goog\"\n        }\n    ],\n    \"x-google-marks\": \"marks values\"\n}`\n\tgopath := os.Getenv(\"GOPATH\")\n\tassert.NotNil(t, gopath)\n\n\tp := New()\n\n\terr := p.ParseGeneralAPIInfo(\"testdata/templated.go\")\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParser_ParseGeneralApiInfoExtensions(t *testing.T) {\n\t// should return an error because extension value is not a valid json\n\tt.Run(\"Test invalid extension value\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texpected := \"annotation @x-google-endpoints need a valid json value\"\n\t\tgopath := os.Getenv(\"GOPATH\")\n\t\tassert.NotNil(t, gopath)\n\n\t\tp := New()\n\n\t\terr := p.ParseGeneralAPIInfo(\"testdata/extensionsFail1.go\")\n\t\tif assert.Error(t, err) {\n\t\t\tassert.Equal(t, expected, err.Error())\n\t\t}\n\t})\n\n\t// should return an error because extension don't have a value\n\tt.Run(\"Test missing extension value\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texpected := \"annotation @x-google-endpoints need a value\"\n\t\tgopath := os.Getenv(\"GOPATH\")\n\t\tassert.NotNil(t, gopath)\n\n\t\tp := New()\n\n\t\terr := p.ParseGeneralAPIInfo(\"testdata/extensionsFail2.go\")\n\t\tif assert.Error(t, err) {\n\t\t\tassert.Equal(t, expected, err.Error())\n\t\t}\n\t})\n}\n\nfunc TestParser_ParseGeneralApiInfoWithOpsInSameFile(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\\nIt has a lot of beautiful features.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"paths\": {}\n}`\n\n\tgopath := os.Getenv(\"GOPATH\")\n\tassert.NotNil(t, gopath)\n\n\tp := New()\n\n\terr := p.ParseGeneralAPIInfo(\"testdata/single_file_api/main.go\")\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParser_ParseGeneralAPIInfoMarkdown(t *testing.T) {\n\tt.Parallel()\n\n\tp := New(SetMarkdownFileDirectory(\"testdata\"))\n\tmainAPIFile := \"testdata/markdown.go\"\n\terr := p.ParseGeneralAPIInfo(mainAPIFile)\n\tassert.NoError(t, err)\n\n\texpected := `{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"Swagger Example API Markdown Description\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"paths\": {},\n    \"tags\": [\n        {\n            \"description\": \"Users Tag Markdown Description\",\n            \"name\": \"users\"\n        }\n    ]\n}`\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n\n\tp = New()\n\n\terr = p.ParseGeneralAPIInfo(mainAPIFile)\n\tassert.Error(t, err)\n}\n\nfunc TestParser_ParseGeneralApiInfoFailed(t *testing.T) {\n\tt.Parallel()\n\n\tgopath := os.Getenv(\"GOPATH\")\n\tassert.NotNil(t, gopath)\n\tp := New()\n\tassert.Error(t, p.ParseGeneralAPIInfo(\"testdata/noexist.go\"))\n}\n\nfunc TestParser_ParseAcceptComment(t *testing.T) {\n\tt.Parallel()\n\n\texpected := []string{\n\t\t\"application/json\",\n\t\t\"text/xml\",\n\t\t\"text/plain\",\n\t\t\"text/html\",\n\t\t\"multipart/form-data\",\n\t\t\"application/x-www-form-urlencoded\",\n\t\t\"application/vnd.api+json\",\n\t\t\"application/x-json-stream\",\n\t\t\"application/octet-stream\",\n\t\t\"image/png\",\n\t\t\"image/jpeg\",\n\t\t\"image/gif\",\n\t\t\"application/xhtml+xml\",\n\t\t\"application/health+json\",\n\t\t\"text/event-stream\",\n\t}\n\n\tcomment := `@Accept json,xml,plain,html,mpfd,x-www-form-urlencoded,json-api,json-stream,octet-stream,png,jpeg,gif,application/xhtml+xml,application/health+json,event-stream`\n\n\tparser := New()\n\tassert.NoError(t, parseGeneralAPIInfo(parser, []string{comment}))\n\tassert.Equal(t, parser.swagger.Consumes, expected)\n\n\tassert.Error(t, parseGeneralAPIInfo(parser, []string{`@Accept cookies,candies`}))\n\n\tparser = New()\n\tassert.NoError(t, parser.ParseAcceptComment(comment[len(acceptAttr)+1:]))\n\tassert.Equal(t, parser.swagger.Consumes, expected)\n}\n\nfunc TestParser_ParseProduceComment(t *testing.T) {\n\tt.Parallel()\n\n\texpected := []string{\n\t\t\"application/json\",\n\t\t\"text/xml\",\n\t\t\"text/plain\",\n\t\t\"text/html\",\n\t\t\"multipart/form-data\",\n\t\t\"application/x-www-form-urlencoded\",\n\t\t\"application/vnd.api+json\",\n\t\t\"application/x-json-stream\",\n\t\t\"application/octet-stream\",\n\t\t\"image/png\",\n\t\t\"image/jpeg\",\n\t\t\"image/gif\",\n\t\t\"application/xhtml+xml\",\n\t\t\"application/health+json\",\n\t\t\"text/event-stream\",\n\t}\n\n\tcomment := `@Produce json,xml,plain,html,mpfd,x-www-form-urlencoded,json-api,json-stream,octet-stream,png,jpeg,gif,application/xhtml+xml,application/health+json,event-stream`\n\n\tparser := New()\n\tassert.NoError(t, parseGeneralAPIInfo(parser, []string{comment}))\n\tassert.Equal(t, parser.swagger.Produces, expected)\n\n\tassert.Error(t, parseGeneralAPIInfo(parser, []string{`@Produce cookies,candies`}))\n\n\tparser = New()\n\tassert.NoError(t, parser.ParseProduceComment(comment[len(produceAttr)+1:]))\n\tassert.Equal(t, parser.swagger.Produces, expected)\n}\n\nfunc TestParser_ParseGeneralAPIInfoCollectionFormat(t *testing.T) {\n\tt.Parallel()\n\n\tparser := New()\n\tassert.NoError(t, parseGeneralAPIInfo(parser, []string{\n\t\t\"@query.collection.format csv\",\n\t}))\n\tassert.Equal(t, parser.collectionFormatInQuery, \"csv\")\n\n\tassert.NoError(t, parseGeneralAPIInfo(parser, []string{\n\t\t\"@query.collection.format tsv\",\n\t}))\n\tassert.Equal(t, parser.collectionFormatInQuery, \"tsv\")\n}\n\nfunc TestParser_ParseGeneralAPITagGroups(t *testing.T) {\n\tt.Parallel()\n\n\tparser := New()\n\tassert.NoError(t, parseGeneralAPIInfo(parser, []string{\n\t\t\"@x-tagGroups [{\\\"name\\\":\\\"General\\\",\\\"tags\\\":[\\\"lanes\\\",\\\"video-recommendations\\\"]}]\",\n\t}))\n\n\texpected := []interface{}{map[string]interface{}{\"name\": \"General\", \"tags\": []interface{}{\"lanes\", \"video-recommendations\"}}}\n\tassert.Equal(t, parser.swagger.Extensions[\"x-tagGroups\"], expected)\n}\n\nfunc TestParser_ParseGeneralAPITagDocs(t *testing.T) {\n\tt.Parallel()\n\n\tparser := New()\n\tassert.Error(t, parseGeneralAPIInfo(parser, []string{\n\t\t\"@tag.name Test\",\n\t\t\"@tag.docs.description Best example documentation\"}))\n\n\tparser = New()\n\terr := parseGeneralAPIInfo(parser, []string{\n\t\t\"@tag.name test\",\n\t\t\"@tag.description A test Tag\",\n\t\t\"@tag.docs.url https://example.com\",\n\t\t\"@tag.docs.description Best example documentation\",\n\t\t\"@tag.x-displayName Test group\"})\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(parser.GetSwagger().Tags, \"\", \"    \")\n\texpected := `[\n    {\n        \"description\": \"A test Tag\",\n        \"name\": \"test\",\n        \"externalDocs\": {\n            \"description\": \"Best example documentation\",\n            \"url\": \"https://example.com\"\n        },\n        \"x-displayName\": \"Test group\"\n    }\n]`\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParser_ParseGeneralAPITagDocsWithTagFilters(t *testing.T) {\n\tt.Parallel()\n\n\tfilterTags := []string{\"test1\", \"!test2\"}\n\n\tcomments := []string{\n\t\t\"@tag.name test1\",\n\t\t\"@tag.description A test1 Tag\",\n\t\t\"@tag.docs.url https://example1.com\",\n\t\t\"@tag.docs.description Best example1 documentation\",\n\t\t\"@tag.name test2\",\n\t\t\"@tag.description A test2 Tag\",\n\t\t\"@tag.docs.url https://example2.com\",\n\t\t\"@tag.docs.description Best example2 documentation\"}\n\n\texpected := `[\n    {\n        \"description\": \"A test1 Tag\",\n        \"name\": \"test1\",\n        \"externalDocs\": {\n            \"description\": \"Best example1 documentation\",\n            \"url\": \"https://example1.com\"\n        }\n    }\n]`\n\n\tfor _, tag := range filterTags {\n\t\tparser := New(SetTags(tag))\n\t\terr := parseGeneralAPIInfo(parser, comments)\n\t\tassert.NoError(t, err)\n\t\tb, _ := json.MarshalIndent(parser.GetSwagger().Tags, \"\", \"    \")\n\t\tassert.Equal(t, expected, string(b))\n\t}\n}\n\nfunc TestParser_ParseGeneralAPISecurity(t *testing.T) {\n\tt.Run(\"ApiKey\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tparser := New()\n\t\tassert.Error(t, parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.apikey ApiKey\"}))\n\n\t\tassert.Error(t, parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.apikey ApiKey\",\n\t\t\t\"@in header\"}))\n\t\tassert.Error(t, parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.apikey ApiKey\",\n\t\t\t\"@name X-API-KEY\"}))\n\n\t\terr := parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.apikey ApiKey\",\n\t\t\t\"@in header\",\n\t\t\t\"@name X-API-KEY\",\n\t\t\t\"@description some\",\n\t\t\t\"\",\n\t\t\t\"@securitydefinitions.oauth2.accessCode OAuth2AccessCode\",\n\t\t\t\"@tokenUrl https://example.com/oauth/token\",\n\t\t\t\"@authorizationUrl https://example.com/oauth/authorize\",\n\t\t\t\"@scope.admin foo\",\n\t\t})\n\t\tassert.NoError(t, err)\n\n\t\tb, _ := json.MarshalIndent(parser.GetSwagger().SecurityDefinitions, \"\", \"    \")\n\t\texpected := `{\n    \"ApiKey\": {\n        \"description\": \"some\",\n        \"type\": \"apiKey\",\n        \"name\": \"X-API-KEY\",\n        \"in\": \"header\"\n    },\n    \"OAuth2AccessCode\": {\n        \"type\": \"oauth2\",\n        \"flow\": \"accessCode\",\n        \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n        \"tokenUrl\": \"https://example.com/oauth/token\",\n        \"scopes\": {\n            \"admin\": \"foo\"\n        }\n    }\n}`\n\t\tassert.Equal(t, expected, string(b))\n\t})\n\n\tt.Run(\"OAuth2Application\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tparser := New()\n\t\tassert.Error(t, parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.oauth2.application OAuth2Application\"}))\n\n\t\terr := parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.oauth2.application OAuth2Application\",\n\t\t\t\"@tokenUrl https://example.com/oauth/token\"})\n\t\tassert.NoError(t, err)\n\t\tb, _ := json.MarshalIndent(parser.GetSwagger().SecurityDefinitions, \"\", \"    \")\n\t\texpected := `{\n    \"OAuth2Application\": {\n        \"type\": \"oauth2\",\n        \"flow\": \"application\",\n        \"tokenUrl\": \"https://example.com/oauth/token\"\n    }\n}`\n\t\tassert.Equal(t, expected, string(b))\n\t})\n\n\tt.Run(\"OAuth2Implicit\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tparser := New()\n\t\tassert.Error(t, parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.oauth2.implicit OAuth2Implicit\"}))\n\n\t\terr := parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.oauth2.implicit OAuth2Implicit\",\n\t\t\t\"@authorizationurl https://example.com/oauth/authorize\"})\n\t\tassert.NoError(t, err)\n\t\tb, _ := json.MarshalIndent(parser.GetSwagger().SecurityDefinitions, \"\", \"    \")\n\t\texpected := `{\n    \"OAuth2Implicit\": {\n        \"type\": \"oauth2\",\n        \"flow\": \"implicit\",\n        \"authorizationUrl\": \"https://example.com/oauth/authorize\"\n    }\n}`\n\t\tassert.Equal(t, expected, string(b))\n\t})\n\n\tt.Run(\"OAuth2Password\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tparser := New()\n\t\tassert.Error(t, parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.oauth2.password OAuth2Password\"}))\n\n\t\terr := parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.oauth2.password OAuth2Password\",\n\t\t\t\"@tokenUrl https://example.com/oauth/token\"})\n\t\tassert.NoError(t, err)\n\t\tb, _ := json.MarshalIndent(parser.GetSwagger().SecurityDefinitions, \"\", \"    \")\n\t\texpected := `{\n    \"OAuth2Password\": {\n        \"type\": \"oauth2\",\n        \"flow\": \"password\",\n        \"tokenUrl\": \"https://example.com/oauth/token\"\n    }\n}`\n\t\tassert.Equal(t, expected, string(b))\n\t})\n\n\tt.Run(\"OAuth2AccessCode\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tparser := New()\n\t\tassert.Error(t, parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.oauth2.accessCode OAuth2AccessCode\"}))\n\n\t\tassert.Error(t, parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.oauth2.accessCode OAuth2AccessCode\",\n\t\t\t\"@tokenUrl https://example.com/oauth/token\"}))\n\n\t\tassert.Error(t, parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.oauth2.accessCode OAuth2AccessCode\",\n\t\t\t\"@authorizationurl https://example.com/oauth/authorize\"}))\n\n\t\terr := parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.oauth2.accessCode OAuth2AccessCode\",\n\t\t\t\"@tokenUrl https://example.com/oauth/token\",\n\t\t\t\"@authorizationurl https://example.com/oauth/authorize\"})\n\t\tassert.NoError(t, err)\n\t\tb, _ := json.MarshalIndent(parser.GetSwagger().SecurityDefinitions, \"\", \"    \")\n\t\texpected := `{\n    \"OAuth2AccessCode\": {\n        \"type\": \"oauth2\",\n        \"flow\": \"accessCode\",\n        \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n        \"tokenUrl\": \"https://example.com/oauth/token\"\n    }\n}`\n\t\tassert.Equal(t, expected, string(b))\n\n\t\tassert.Error(t, parseGeneralAPIInfo(parser, []string{\n\t\t\t\"@securitydefinitions.oauth2.accessCode OAuth2AccessCode\",\n\t\t\t\"@tokenUrl https://example.com/oauth/token\",\n\t\t\t\"@authorizationurl https://example.com/oauth/authorize\",\n\t\t\t\"@scope.read,write Multiple scope\"}))\n\t})\n}\n\nfunc TestParser_RefWithOtherPropertiesIsWrappedInAllOf(t *testing.T) {\n\tt.Run(\"Readonly\", func(t *testing.T) {\n\t\tsrc := `\npackage main\n\ntype Teacher struct {\n\tName string\n} //@name Teacher\n\ntype Student struct {\n\tName string\n\tAge int ` + \"`readonly:\\\"true\\\"`\" + `\n\tTeacher Teacher ` + \"`readonly:\\\"true\\\"`\" + `\n\tOtherTeacher Teacher\n} //@name Student\n\n// @Success 200 {object} Student\n// @Router /test [get]\nfunc Fun()  {\n\n}\n`\n\t\texpected := `{\n    \"info\": {\n        \"contact\": {}\n    },\n    \"paths\": {\n        \"/test\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/Student\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"Student\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"age\": {\n                    \"type\": \"integer\",\n                    \"readOnly\": true\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                },\n                \"otherTeacher\": {\n                    \"$ref\": \"#/definitions/Teacher\"\n                },\n                \"teacher\": {\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/Teacher\"\n                        }\n                    ],\n                    \"readOnly\": true\n                }\n            }\n        },\n        \"Teacher\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}`\n\n\t\tp := New()\n\t\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\n\t\t_, err := p.packages.ParseTypes()\n\t\tassert.NoError(t, err)\n\n\t\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\t\tassert.NoError(t, err)\n\n\t\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\t\tassert.Equal(t, expected, string(b))\n\t})\n}\n\nfunc TestGetAllGoFileInfo(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/pet\"\n\n\tp := New()\n\terr := p.getAllGoFileInfo(\"testdata\", searchDir)\n\n\tassert.NoError(t, err)\n\tassert.Equal(t, 2, len(p.packages.files))\n}\n\nfunc TestParser_ParseType(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/simple/\"\n\n\tp := New()\n\terr := p.getAllGoFileInfo(\"testdata\", searchDir)\n\tassert.NoError(t, err)\n\n\t_, err = p.packages.ParseTypes()\n\n\tassert.NoError(t, err)\n\tassert.NotNil(t, p.packages.uniqueDefinitions[\"api.Pet3\"])\n\tassert.NotNil(t, p.packages.uniqueDefinitions[\"web.Pet\"])\n\tassert.NotNil(t, p.packages.uniqueDefinitions[\"web.Pet2\"])\n}\n\nfunc TestParseSimpleApi1(t *testing.T) {\n\tt.Parallel()\n\n\texpected, err := os.ReadFile(\"testdata/simple/expected.json\")\n\tassert.NoError(t, err)\n\tsearchDir := \"testdata/simple\"\n\tp := New()\n\tp.PropNamingStrategy = PascalCase\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"  \")\n\tassert.JSONEq(t, string(expected), string(b))\n}\n\nfunc TestParseInterfaceAndError(t *testing.T) {\n\tt.Parallel()\n\n\texpected, err := os.ReadFile(\"testdata/error/expected.json\")\n\tassert.NoError(t, err)\n\tsearchDir := \"testdata/error\"\n\tp := New()\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"  \")\n\tassert.JSONEq(t, string(expected), string(b))\n}\n\nfunc TestParseSimpleApi_ForSnakecase(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {\n        \"/file/upload\": {\n            \"post\": {\n                \"description\": \"Upload file\",\n                \"consumes\": [\n                    \"multipart/form-data\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Upload file\",\n                \"operationId\": \"file.upload\",\n                \"parameters\": [\n                    {\n                        \"type\": \"file\",\n                        \"description\": \"this is a test file\",\n                        \"name\": \"file\",\n                        \"in\": \"formData\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-string-by-int/{some_id}\": {\n            \"get\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add a new pet to the store\",\n                \"operationId\": \"get-string-by-int\",\n                \"parameters\": [\n                    {\n                        \"type\": \"integer\",\n                        \"format\": \"int64\",\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    },\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.Pet\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-struct-array-by-string/{some_id}\": {\n            \"get\": {\n                \"description\": \"get struct array by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"operationId\": \"get-struct-array-by-string\",\n                \"parameters\": [\n                    {\n                        \"type\": \"string\",\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    },\n                    {\n                        \"enum\": [\n                            1,\n                            2,\n                            3\n                        ],\n                        \"type\": \"integer\",\n                        \"description\": \"Category\",\n                        \"name\": \"category\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"minimum\": 0,\n                        \"type\": \"integer\",\n                        \"default\": 0,\n                        \"description\": \"Offset\",\n                        \"name\": \"offset\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"maximum\": 50,\n                        \"type\": \"integer\",\n                        \"default\": 10,\n                        \"description\": \"Limit\",\n                        \"name\": \"limit\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"maxLength\": 50,\n                        \"minLength\": 1,\n                        \"type\": \"string\",\n                        \"default\": \"\\\"\\\"\",\n                        \"description\": \"q\",\n                        \"name\": \"q\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                },\n                \"security\": [\n                    {\n                        \"ApiKeyAuth\": []\n                    },\n                    {\n                        \"BasicAuth\": []\n                    },\n                    {\n                        \"OAuth2Application\": [\n                            \"write\"\n                        ]\n                    },\n                    {\n                        \"OAuth2Implicit\": [\n                            \"read\",\n                            \"admin\"\n                        ]\n                    },\n                    {\n                        \"OAuth2AccessCode\": [\n                            \"read\"\n                        ]\n                    },\n                    {\n                        \"OAuth2Password\": [\n                            \"admin\"\n                        ]\n                    }\n                ]\n            }\n        }\n    },\n    \"definitions\": {\n        \"web.APIError\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"created_at\": {\n                    \"type\": \"string\"\n                },\n                \"error_code\": {\n                    \"type\": \"integer\"\n                },\n                \"error_message\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.Pet\": {\n            \"type\": \"object\",\n            \"required\": [\n                \"price\"\n            ],\n            \"properties\": {\n                \"birthday\": {\n                    \"type\": \"integer\"\n                },\n                \"category\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"id\": {\n                            \"type\": \"integer\",\n                            \"example\": 1\n                        },\n                        \"name\": {\n                            \"type\": \"string\",\n                            \"example\": \"category_name\"\n                        },\n                        \"photo_urls\": {\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"string\",\n                                \"format\": \"url\"\n                            },\n                            \"example\": [\n                                \"http://test/image/1.jpg\",\n                                \"http://test/image/2.jpg\"\n                            ]\n                        },\n                        \"small_category\": {\n                            \"type\": \"object\",\n                            \"required\": [\n                                \"name\"\n                            ],\n                            \"properties\": {\n                                \"id\": {\n                                    \"type\": \"integer\",\n                                    \"example\": 1\n                                },\n                                \"name\": {\n                                    \"type\": \"string\",\n                                    \"example\": \"detail_category_name\"\n                                },\n                                \"photo_urls\": {\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"type\": \"string\"\n                                    },\n                                    \"example\": [\n                                        \"http://test/image/1.jpg\",\n                                        \"http://test/image/2.jpg\"\n                                    ]\n                                }\n                            }\n                        }\n                    }\n                },\n                \"coeffs\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"number\"\n                    }\n                },\n                \"custom_string\": {\n                    \"type\": \"string\"\n                },\n                \"custom_string_arr\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    }\n                },\n                \"data\": {},\n                \"decimal\": {\n                    \"type\": \"number\"\n                },\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\",\n                    \"example\": 1\n                },\n                \"is_alive\": {\n                    \"type\": \"boolean\",\n                    \"example\": true\n                },\n                \"name\": {\n                    \"type\": \"string\",\n                    \"example\": \"poti\"\n                },\n                \"null_int\": {\n                    \"type\": \"integer\"\n                },\n                \"pets\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet2\"\n                    }\n                },\n                \"pets2\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet2\"\n                    }\n                },\n                \"photo_urls\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    },\n                    \"example\": [\n                        \"http://test/image/1.jpg\",\n                        \"http://test/image/2.jpg\"\n                    ]\n                },\n                \"price\": {\n                    \"type\": \"number\",\n                    \"maximum\": 130,\n                    \"minimum\": 0,\n                    \"multipleOf\": 0.01,\n                    \"example\": 3.25\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                },\n                \"tags\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Tag\"\n                    }\n                },\n                \"uuid\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.Pet2\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"deleted_at\": {\n                    \"type\": \"string\"\n                },\n                \"id\": {\n                    \"type\": \"integer\"\n                },\n                \"middle_name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.RevValue\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"integer\"\n                },\n                \"err\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int32\"\n                },\n                \"status\": {\n                    \"type\": \"boolean\"\n                }\n            }\n        },\n        \"web.Tag\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                },\n                \"pets\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet\"\n                    }\n                }\n            }\n        }\n    },\n    \"securityDefinitions\": {\n        \"ApiKeyAuth\": {\n            \"type\": \"apiKey\",\n            \"name\": \"Authorization\",\n            \"in\": \"header\"\n        },\n        \"BasicAuth\": {\n            \"type\": \"basic\"\n        },\n        \"OAuth2AccessCode\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"accessCode\",\n            \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\"\n            }\n        },\n        \"OAuth2Application\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"application\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"write\": \"Grants write access\"\n            }\n        },\n        \"OAuth2Implicit\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"implicit\",\n            \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"write\": \"Grants write access\"\n            }\n        },\n        \"OAuth2Password\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"password\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"read\": \"Grants read access\",\n                \"write\": \"Grants write access\"\n            }\n        }\n    }\n}`\n\tsearchDir := \"testdata/simple2\"\n\tp := New()\n\tp.PropNamingStrategy = SnakeCase\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseSimpleApi_ForLowerCamelcase(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {\n        \"/file/upload\": {\n            \"post\": {\n                \"description\": \"Upload file\",\n                \"consumes\": [\n                    \"multipart/form-data\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Upload file\",\n                \"operationId\": \"file.upload\",\n                \"parameters\": [\n                    {\n                        \"type\": \"file\",\n                        \"description\": \"this is a test file\",\n                        \"name\": \"file\",\n                        \"in\": \"formData\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-string-by-int/{some_id}\": {\n            \"get\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add a new pet to the store\",\n                \"operationId\": \"get-string-by-int\",\n                \"parameters\": [\n                    {\n                        \"type\": \"integer\",\n                        \"format\": \"int64\",\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    },\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.Pet\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-struct-array-by-string/{some_id}\": {\n            \"get\": {\n                \"description\": \"get struct array by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"operationId\": \"get-struct-array-by-string\",\n                \"parameters\": [\n                    {\n                        \"type\": \"string\",\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    },\n                    {\n                        \"enum\": [\n                            1,\n                            2,\n                            3\n                        ],\n                        \"type\": \"integer\",\n                        \"description\": \"Category\",\n                        \"name\": \"category\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"minimum\": 0,\n                        \"type\": \"integer\",\n                        \"default\": 0,\n                        \"description\": \"Offset\",\n                        \"name\": \"offset\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"maximum\": 50,\n                        \"type\": \"integer\",\n                        \"default\": 10,\n                        \"description\": \"Limit\",\n                        \"name\": \"limit\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"maxLength\": 50,\n                        \"minLength\": 1,\n                        \"type\": \"string\",\n                        \"default\": \"\\\"\\\"\",\n                        \"description\": \"q\",\n                        \"name\": \"q\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                },\n                \"security\": [\n                    {\n                        \"ApiKeyAuth\": []\n                    },\n                    {\n                        \"BasicAuth\": []\n                    },\n                    {\n                        \"OAuth2Application\": [\n                            \"write\"\n                        ]\n                    },\n                    {\n                        \"OAuth2Implicit\": [\n                            \"read\",\n                            \"admin\"\n                        ]\n                    },\n                    {\n                        \"OAuth2AccessCode\": [\n                            \"read\"\n                        ]\n                    },\n                    {\n                        \"OAuth2Password\": [\n                            \"admin\"\n                        ]\n                    }\n                ]\n            }\n        }\n    },\n    \"definitions\": {\n        \"web.APIError\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"createdAt\": {\n                    \"type\": \"string\"\n                },\n                \"errorCode\": {\n                    \"type\": \"integer\"\n                },\n                \"errorMessage\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.Pet\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"category\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"id\": {\n                            \"type\": \"integer\",\n                            \"example\": 1\n                        },\n                        \"name\": {\n                            \"type\": \"string\",\n                            \"example\": \"category_name\"\n                        },\n                        \"photoURLs\": {\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"string\",\n                                \"format\": \"url\"\n                            },\n                            \"example\": [\n                                \"http://test/image/1.jpg\",\n                                \"http://test/image/2.jpg\"\n                            ]\n                        },\n                        \"smallCategory\": {\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"id\": {\n                                    \"type\": \"integer\",\n                                    \"example\": 1\n                                },\n                                \"name\": {\n                                    \"type\": \"string\",\n                                    \"example\": \"detail_category_name\"\n                                },\n                                \"photoURLs\": {\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"type\": \"string\"\n                                    },\n                                    \"example\": [\n                                        \"http://test/image/1.jpg\",\n                                        \"http://test/image/2.jpg\"\n                                    ]\n                                }\n                            }\n                        }\n                    }\n                },\n                \"data\": {},\n                \"decimal\": {\n                    \"type\": \"number\"\n                },\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\",\n                    \"example\": 1\n                },\n                \"isAlive\": {\n                    \"type\": \"boolean\",\n                    \"example\": true\n                },\n                \"name\": {\n                    \"type\": \"string\",\n                    \"example\": \"poti\"\n                },\n                \"pets\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet2\"\n                    }\n                },\n                \"pets2\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet2\"\n                    }\n                },\n                \"photoURLs\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    },\n                    \"example\": [\n                        \"http://test/image/1.jpg\",\n                        \"http://test/image/2.jpg\"\n                    ]\n                },\n                \"price\": {\n                    \"type\": \"number\",\n                    \"multipleOf\": 0.01,\n                    \"example\": 3.25\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                },\n                \"tags\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Tag\"\n                    }\n                },\n                \"uuid\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.Pet2\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"deletedAt\": {\n                    \"type\": \"string\"\n                },\n                \"id\": {\n                    \"type\": \"integer\"\n                },\n                \"middleName\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.RevValue\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"integer\"\n                },\n                \"err\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int32\"\n                },\n                \"status\": {\n                    \"type\": \"boolean\"\n                }\n            }\n        },\n        \"web.Tag\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                },\n                \"pets\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet\"\n                    }\n                }\n            }\n        }\n    },\n    \"securityDefinitions\": {\n        \"ApiKeyAuth\": {\n            \"type\": \"apiKey\",\n            \"name\": \"Authorization\",\n            \"in\": \"header\"\n        },\n        \"BasicAuth\": {\n            \"type\": \"basic\"\n        },\n        \"OAuth2AccessCode\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"accessCode\",\n            \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\"\n            }\n        },\n        \"OAuth2Application\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"application\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"write\": \"Grants write access\"\n            }\n        },\n        \"OAuth2Implicit\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"implicit\",\n            \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"write\": \"Grants write access\"\n            }\n        },\n        \"OAuth2Password\": {\n            \"type\": \"oauth2\",\n            \"flow\": \"password\",\n            \"tokenUrl\": \"https://example.com/oauth/token\",\n            \"scopes\": {\n                \"admin\": \"Grants read and write access to administrative information\",\n                \"read\": \"Grants read access\",\n                \"write\": \"Grants write access\"\n            }\n        }\n    }\n}`\n\tsearchDir := \"testdata/simple3\"\n\tp := New()\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseStructComment(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:4000\",\n    \"basePath\": \"/api\",\n    \"paths\": {\n        \"/posts/{post_id}\": {\n            \"get\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add a new pet to the store\",\n                \"parameters\": [\n                    {\n                        \"type\": \"integer\",\n                        \"format\": \"int64\",\n                        \"description\": \"Some ID\",\n                        \"name\": \"post_id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"web.APIError\": {\n            \"description\": \"API error with information about it\",\n            \"type\": \"object\",\n            \"properties\": {\n                \"createdAt\": {\n                    \"description\": \"Error time\",\n                    \"type\": \"string\"\n                },\n                \"error\": {\n                    \"description\": \"Error an Api error\",\n                    \"type\": \"string\"\n                },\n                \"errorCtx\": {\n                    \"description\": \"Error ` + \"`\" + `context` + \"`\" + ` tick comment\",\n                    \"type\": \"string\"\n                },\n                \"errorNo\": {\n                    \"description\": \"Error ` + \"`\" + `number` + \"`\" + ` tick comment\",\n                    \"type\": \"integer\",\n                    \"format\": \"int64\"\n                }\n            }\n        }\n    }\n}`\n\tsearchDir := \"testdata/struct_comment\"\n\tp := New()\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseNonExportedJSONFields(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:4000\",\n    \"basePath\": \"/api\",\n    \"paths\": {\n        \"/so-something\": {\n            \"get\": {\n                \"description\": \"Does something, but internal (non-exported) fields inside a struct won't be marshaled into JSON\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Call DoSomething\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/main.MyStruct\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"main.MyStruct\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"description\": \"Post data\",\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"name\": {\n                            \"description\": \"Post tag\",\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"string\"\n                            }\n                        }\n                    }\n                },\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\",\n                    \"example\": 1\n                },\n                \"name\": {\n                    \"description\": \"Post name\",\n                    \"type\": \"string\",\n                    \"example\": \"poti\"\n                }\n            }\n        }\n    }\n}`\n\n\tsearchDir := \"testdata/non_exported_json_fields\"\n\tp := New()\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParsePetApi(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\n    \"schemes\": [\n        \"http\",\n        \"https\"\n    ],\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.  You can find out more about     Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).      For this sample, you can use the api key 'special-key' to test the authorization     filters.\",\n        \"title\": \"Swagger Petstore\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"email\": \"apiteam@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {}\n}`\n\tsearchDir := \"testdata/pet\"\n\tp := New()\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseModelAsTypeAlias(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {\n        \"/testapi/time-as-time-container\": {\n            \"get\": {\n                \"description\": \"test container with time and time alias\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Get container with time and time alias\",\n                \"operationId\": \"time-as-time-container\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/data.TimeContainer\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"data.TimeContainer\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"created_at\": {\n                    \"type\": \"string\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                },\n                \"timestamp\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}`\n\tsearchDir := \"testdata/alias_type\"\n\tp := New()\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseComposition(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/composition\"\n\tp := New()\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\n\t// windows will fail: \\r\\n \\n\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseImportAliases(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/alias_import\"\n\tp := New()\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\t// windows will fail: \\r\\n \\n\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseTypeOverrides(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/global_override\"\n\tp := New(SetOverrides(map[string]string{\n\t\t\"github.com/swaggo/swag/testdata/global_override/types.Application\":  \"string\",\n\t\t\"github.com/swaggo/swag/testdata/global_override/types.Application2\": \"github.com/swaggo/swag/testdata/global_override/othertypes.Application\",\n\t\t\"github.com/swaggo/swag/testdata/global_override/types.ShouldSkip\":   \"\",\n\t}))\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\t//windows will fail: \\r\\n \\n\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestGlobalSecurity(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/global_security\"\n\tp := New()\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"  \")\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseNested(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/nested\"\n\tp := New(SetParseDependency(1))\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseDuplicated(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/duplicated\"\n\tp := New(SetParseDependency(1))\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.Errorf(t, err, \"duplicated @id declarations successfully found\")\n}\n\nfunc TestParseDuplicatedOtherMethods(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/duplicated2\"\n\tp := New(SetParseDependency(1))\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.Errorf(t, err, \"duplicated @id declarations successfully found\")\n}\n\nfunc TestParseDuplicatedFunctionScoped(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/duplicated_function_scoped\"\n\tp := New(SetParseDependency(1))\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.Errorf(t, err, \"duplicated @id declarations successfully found\")\n}\n\nfunc TestParseConflictSchemaName(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/conflict_name\"\n\tp := New(SetParseDependency(1))\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseExternalModels(t *testing.T) {\n\tsearchDir := \"testdata/external_models/main\"\n\tmainAPIFile := \"main.go\"\n\tp := New(SetParseDependency(1))\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\t//ioutil.WriteFile(\"./testdata/external_models/main/expected.json\",b,0777)\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParseGoList(t *testing.T) {\n\tmainAPIFile := \"main.go\"\n\tp := New(ParseUsingGoList(true), SetParseDependency(1))\n\tgo111moduleEnv := os.Getenv(\"GO111MODULE\")\n\n\tcases := []struct {\n\t\tname      string\n\t\tgomodule  bool\n\t\tsearchDir string\n\t\terr       error\n\t\trun       func(searchDir string) error\n\t}{\n\t\t{\n\t\t\tname:      \"disableGOMODULE\",\n\t\t\tgomodule:  false,\n\t\t\tsearchDir: \"testdata/golist_disablemodule\",\n\t\t\trun: func(searchDir string) error {\n\t\t\t\treturn p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"enableGOMODULE\",\n\t\t\tgomodule:  true,\n\t\t\tsearchDir: \"testdata/golist\",\n\t\t\trun: func(searchDir string) error {\n\t\t\t\treturn p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"invalid_main\",\n\t\t\tgomodule:  true,\n\t\t\tsearchDir: \"testdata/golist_invalid\",\n\t\t\terr:       errors.New(\"no such file or directory\"),\n\t\t\trun: func(searchDir string) error {\n\t\t\t\treturn p.ParseAPI(searchDir, \"invalid/main.go\", defaultParseDepth)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"internal_invalid_pkg\",\n\t\t\tgomodule:  true,\n\t\t\tsearchDir: \"testdata/golist_invalid\",\n\t\t\terr:       errors.New(\"expected 'package', found This\"),\n\t\t\trun: func(searchDir string) error {\n\t\t\t\tmockErrGoFile := \"testdata/golist_invalid/err.go\"\n\t\t\t\tf, err := os.OpenFile(mockErrGoFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tdefer f.Close()\n\t\t\t\t_, err = f.Write([]byte(`package invalid\n\nfunction a() {}`))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tdefer os.Remove(mockErrGoFile)\n\t\t\t\treturn p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"invalid_pkg\",\n\t\t\tgomodule:  true,\n\t\t\tsearchDir: \"testdata/golist_invalid\",\n\t\t\terr:       errors.New(\"expected 'package', found This\"),\n\t\t\trun: func(searchDir string) error {\n\t\t\t\tmockErrGoFile := \"testdata/invalid_external_pkg/invalid/err.go\"\n\t\t\t\tf, err := os.OpenFile(mockErrGoFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tdefer f.Close()\n\t\t\t\t_, err = f.Write([]byte(`package invalid\n\nfunction a() {}`))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tdefer os.Remove(mockErrGoFile)\n\t\t\t\treturn p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, c := range cases {\n\t\tt.Run(c.name, func(t *testing.T) {\n\t\t\tif c.gomodule {\n\t\t\t\tos.Setenv(\"GO111MODULE\", \"on\")\n\t\t\t} else {\n\t\t\t\tos.Setenv(\"GO111MODULE\", \"off\")\n\t\t\t}\n\t\t\terr := c.run(c.searchDir)\n\t\t\tos.Setenv(\"GO111MODULE\", go111moduleEnv)\n\t\t\tif c.err == nil {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t} else {\n\t\t\t\tassert.Error(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParser_ParseStructArrayObject(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage api\n\ntype Response struct {\n\tCode int\n\tTable [][]string\n\tData []struct{\n\t\tField1 uint\n\t\tField2 string\n\t}\n}\n\n// @Success 200 {object} Response\n// @Router /api/{id} [get]\nfunc Test(){\n}\n`\n\texpected := `{\n   \"api.Response\": {\n      \"type\": \"object\",\n      \"properties\": {\n         \"code\": {\n            \"type\": \"integer\"\n         },\n         \"data\": {\n            \"type\": \"array\",\n            \"items\": {\n               \"type\": \"object\",\n               \"properties\": {\n                  \"field1\": {\n                     \"type\": \"integer\"\n                  },\n                  \"field2\": {\n                     \"type\": \"string\"\n                  }\n               }\n            }\n         },\n         \"table\": {\n            \"type\": \"array\",\n            \"items\": {\n               \"type\": \"array\",\n               \"items\": {\n                  \"type\": \"string\"\n               }\n            }\n         }\n      }\n   }\n}`\n\n\tp := New()\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\t_, err := p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tout, err := json.MarshalIndent(p.swagger.Definitions, \"\", \"   \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, expected, string(out))\n\n}\n\nfunc TestParser_ParseEmbededStruct(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage api\n\ntype Response struct {\n\trest.ResponseWrapper\n}\n\n// @Success 200 {object} Response\n// @Router /api/{id} [get]\nfunc Test(){\n}\n`\n\trestsrc := `\npackage rest\n\ntype ResponseWrapper struct {\n\tStatus   string\n\tCode     int\n\tMessages []string\n\tResult   interface{}\n}\n`\n\texpected := `{\n   \"api.Response\": {\n      \"type\": \"object\",\n      \"properties\": {\n         \"code\": {\n            \"type\": \"integer\"\n         },\n         \"messages\": {\n            \"type\": \"array\",\n            \"items\": {\n               \"type\": \"string\"\n            }\n         },\n         \"result\": {},\n         \"status\": {\n            \"type\": \"string\"\n         }\n      }\n   }\n}`\n\tparser := New(SetParseDependency(1))\n\n\t_ = parser.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\n\t_ = parser.packages.ParseFile(\"rest\", \"rest/rest.go\", restsrc, ParseAll)\n\n\t_, err := parser.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = parser.packages.RangeFiles(parser.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tout, err := json.MarshalIndent(parser.swagger.Definitions, \"\", \"   \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, expected, string(out))\n\n}\n\nfunc TestParser_ParseStructPointerMembers(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage api\n\ntype Child struct {\n\tName string\n}\n\ntype Parent struct {\n\tTest1 *string  //test1\n\tTest2 *Child   //test2\n}\n\n// @Success 200 {object} Parent\n// @Router /api/{id} [get]\nfunc Test(){\n}\n`\n\n\texpected := `{\n   \"api.Child\": {\n      \"type\": \"object\",\n      \"properties\": {\n         \"name\": {\n            \"type\": \"string\"\n         }\n      }\n   },\n   \"api.Parent\": {\n      \"type\": \"object\",\n      \"properties\": {\n         \"test1\": {\n            \"description\": \"test1\",\n            \"type\": \"string\"\n         },\n         \"test2\": {\n            \"description\": \"test2\",\n            \"allOf\": [\n               {\n                  \"$ref\": \"#/definitions/api.Child\"\n               }\n            ]\n         }\n      }\n   }\n}`\n\tp := New()\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\t_, err := p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tout, err := json.MarshalIndent(p.swagger.Definitions, \"\", \"   \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, expected, string(out))\n}\n\nfunc TestParser_ParseStructMapMember(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage api\n\ntype MyMapType map[string]string\n\ntype Child struct {\n\tName string\n}\n\ntype Parent struct {\n\tTest1 map[string]interface{}  //test1\n\tTest2 map[string]string\t\t  //test2\n\tTest3 map[string]*string\t  //test3\n\tTest4 map[string]Child\t\t  //test4\n\tTest5 map[string]*Child\t\t  //test5\n\tTest6 MyMapType\t\t\t\t  //test6\n\tTest7 []Child\t\t\t\t  //test7\n\tTest8 []*Child\t\t\t\t  //test8\n\tTest9 []map[string]string\t  //test9\n}\n\n// @Success 200 {object} Parent\n// @Router /api/{id} [get]\nfunc Test(){\n}\n`\n\texpected := `{\n   \"api.Child\": {\n      \"type\": \"object\",\n      \"properties\": {\n         \"name\": {\n            \"type\": \"string\"\n         }\n      }\n   },\n   \"api.MyMapType\": {\n      \"type\": \"object\",\n      \"additionalProperties\": {\n         \"type\": \"string\"\n      }\n   },\n   \"api.Parent\": {\n      \"type\": \"object\",\n      \"properties\": {\n         \"test1\": {\n            \"description\": \"test1\",\n            \"type\": \"object\",\n            \"additionalProperties\": true\n         },\n         \"test2\": {\n            \"description\": \"test2\",\n            \"type\": \"object\",\n            \"additionalProperties\": {\n               \"type\": \"string\"\n            }\n         },\n         \"test3\": {\n            \"description\": \"test3\",\n            \"type\": \"object\",\n            \"additionalProperties\": {\n               \"type\": \"string\"\n            }\n         },\n         \"test4\": {\n            \"description\": \"test4\",\n            \"type\": \"object\",\n            \"additionalProperties\": {\n               \"$ref\": \"#/definitions/api.Child\"\n            }\n         },\n         \"test5\": {\n            \"description\": \"test5\",\n            \"type\": \"object\",\n            \"additionalProperties\": {\n               \"$ref\": \"#/definitions/api.Child\"\n            }\n         },\n         \"test6\": {\n            \"description\": \"test6\",\n            \"allOf\": [\n               {\n                  \"$ref\": \"#/definitions/api.MyMapType\"\n               }\n            ]\n         },\n         \"test7\": {\n            \"description\": \"test7\",\n            \"type\": \"array\",\n            \"items\": {\n               \"$ref\": \"#/definitions/api.Child\"\n            }\n         },\n         \"test8\": {\n            \"description\": \"test8\",\n            \"type\": \"array\",\n            \"items\": {\n               \"$ref\": \"#/definitions/api.Child\"\n            }\n         },\n         \"test9\": {\n            \"description\": \"test9\",\n            \"type\": \"array\",\n            \"items\": {\n               \"type\": \"object\",\n               \"additionalProperties\": {\n                  \"type\": \"string\"\n               }\n            }\n         }\n      }\n   }\n}`\n\tp := New()\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\n\t_, err := p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tout, err := json.MarshalIndent(p.swagger.Definitions, \"\", \"   \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, expected, string(out))\n}\n\nfunc TestParser_ParseRouterApiInfoErr(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Accept unknown\nfunc Test(){\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.Error(t, err)\n}\n\nfunc TestParser_ParseRouterApiGet(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Router /api/{id} [get]\nfunc Test(){\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tps := p.swagger.Paths.Paths\n\n\tval, ok := ps[\"/api/{id}\"]\n\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Get)\n}\n\nfunc TestParser_ParseRouterApiPOST(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Router /api/{id} [post]\nfunc Test(){\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tps := p.swagger.Paths.Paths\n\n\tval, ok := ps[\"/api/{id}\"]\n\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Post)\n}\n\nfunc TestParser_ParseRouterApiDELETE(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Router /api/{id} [delete]\nfunc Test(){\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tps := p.swagger.Paths.Paths\n\n\tval, ok := ps[\"/api/{id}\"]\n\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Delete)\n}\n\nfunc TestParser_ParseRouterApiPUT(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Router /api/{id} [put]\nfunc Test(){\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tps := p.swagger.Paths.Paths\n\n\tval, ok := ps[\"/api/{id}\"]\n\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Put)\n}\n\nfunc TestParser_ParseRouterApiPATCH(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Router /api/{id} [patch]\nfunc Test(){\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tps := p.swagger.Paths.Paths\n\n\tval, ok := ps[\"/api/{id}\"]\n\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Patch)\n}\n\nfunc TestParser_ParseRouterApiHead(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Router /api/{id} [head]\nfunc Test(){\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\tps := p.swagger.Paths.Paths\n\n\tval, ok := ps[\"/api/{id}\"]\n\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Head)\n}\n\nfunc TestParser_ParseRouterApiOptions(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Router /api/{id} [options]\nfunc Test(){\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tps := p.swagger.Paths.Paths\n\n\tval, ok := ps[\"/api/{id}\"]\n\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Options)\n}\n\nfunc TestParser_ParseRouterApiMultipleRoutesForSameFunction(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Router /api/v1/{id} [get]\n// @Router /api/v2/{id} [post]\nfunc Test(){\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tps := p.swagger.Paths.Paths\n\n\tval, ok := ps[\"/api/v1/{id}\"]\n\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Get)\n\n\tval, ok = ps[\"/api/v2/{id}\"]\n\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Post)\n}\n\nfunc TestParser_ParseRouterApiMultiple(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Router /api/{id} [get]\nfunc Test1(){\n}\n\n// @Router /api/{id} [patch]\nfunc Test2(){\n}\n\n// @Router /api/{id} [delete]\nfunc Test3(){\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tps := p.swagger.Paths.Paths\n\n\tval, ok := ps[\"/api/{id}\"]\n\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Get)\n\tassert.NotNil(t, val.Patch)\n\tassert.NotNil(t, val.Delete)\n}\n\nfunc TestParser_ParseRouterApiMultiplePathsWithMultipleParams(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Success 200\n// @Param group_id path int true \"Group ID\"\n// @Param user_id  path int true \"User ID\"\n// @Router /examples/groups/{group_id}/user/{user_id}/address [get]\n// @Router /examples/user/{user_id}/address [get]\nfunc Test(){\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tps := p.swagger.Paths.Paths\n\n\tval, ok := ps[\"/examples/groups/{group_id}/user/{user_id}/address\"]\n\n\tassert.True(t, ok)\n\tassert.Equal(t, 2, len(val.Get.Parameters))\n\n\tval, ok = ps[\"/examples/user/{user_id}/address\"]\n\n\tassert.True(t, ok)\n\tassert.Equal(t, 1, len(val.Get.Parameters))\n}\n\n// func TestParseDeterministic(t *testing.T) {\n// \tmainAPIFile := \"main.go\"\n// \tfor _, searchDir := range []string{\n// \t\t\"testdata/simple\",\n// \t\t\"testdata/model_not_under_root/cmd\",\n// \t} {\n// \t\tt.Run(searchDir, func(t *testing.T) {\n// \t\t\tvar expected string\n\n// \t\t\t// run the same code 100 times and check that the output is the same every time\n// \t\t\tfor i := 0; i < 100; i++ {\n// \t\t\t\tp := New()\n// \t\t\t\tp.PropNamingStrategy = PascalCase\n// \t\t\t\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n// \t\t\t\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n// \t\t\t\tassert.NotEqual(t, \"\", string(b))\n\n// \t\t\t\tif expected == \"\" {\n// \t\t\t\t\texpected = string(b)\n// \t\t\t\t}\n\n// \t\t\t\tassert.Equal(t, expected, string(b))\n// \t\t\t}\n// \t\t})\n// \t}\n// }\n\nfunc TestParser_ParseRouterApiDuplicateRoute(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage api\n\nimport (\n\t\"net/http\"\n)\n\n// @Router /api/endpoint [get]\nfunc FunctionOne(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Router /api/endpoint [get]\nfunc FunctionTwo(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n`\n\tp := New(SetStrict(true))\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.EqualError(t, err, \"route GET /api/endpoint is declared multiple times\")\n\n\tp = New()\n\terr = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n}\n\nfunc TestApiParseTag(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/tags\"\n\tp := New(SetMarkdownFileDirectory(searchDir))\n\tp.PropNamingStrategy = PascalCase\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\tif len(p.swagger.Tags) != 3 {\n\t\tt.Error(\"Number of tags did not match\")\n\t}\n\n\tdogs := p.swagger.Tags[0]\n\tif dogs.TagProps.Name != \"dogs\" || dogs.TagProps.Description != \"Dogs are cool\" {\n\t\tt.Error(\"Failed to parse dogs name or description\")\n\t}\n\n\tcats := p.swagger.Tags[1]\n\tif cats.TagProps.Name != \"cats\" || cats.TagProps.Description != \"Cats are the devil\" {\n\t\tt.Error(\"Failed to parse cats name or description\")\n\t}\n\n\tif cats.TagProps.ExternalDocs.URL != \"https://google.de\" || cats.TagProps.ExternalDocs.Description != \"google is super useful to find out that cats are evil!\" {\n\t\tt.Error(\"URL: \", cats.TagProps.ExternalDocs.URL)\n\t\tt.Error(\"Description: \", cats.TagProps.ExternalDocs.Description)\n\t\tt.Error(\"Failed to parse cats external documentation\")\n\t}\n}\n\nfunc TestApiParseTag_NonExistendTag(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/tags_nonexistend_tag\"\n\tp := New(SetMarkdownFileDirectory(searchDir))\n\tp.PropNamingStrategy = PascalCase\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.Error(t, err)\n}\n\nfunc TestParseTagMarkdownDescription(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/tags\"\n\tp := New(SetMarkdownFileDirectory(searchDir))\n\tp.PropNamingStrategy = PascalCase\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tif err != nil {\n\t\tt.Error(\"Failed to parse api description: \" + err.Error())\n\t}\n\n\tif len(p.swagger.Tags) != 3 {\n\t\tt.Error(\"Number of tags did not match\")\n\t}\n\n\tapes := p.swagger.Tags[2]\n\tif apes.TagProps.Description == \"\" {\n\t\tt.Error(\"Failed to parse tag description markdown file\")\n\t}\n}\n\nfunc TestParseApiMarkdownDescription(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/tags\"\n\tp := New(SetMarkdownFileDirectory(searchDir))\n\tp.PropNamingStrategy = PascalCase\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tif err != nil {\n\t\tt.Error(\"Failed to parse api description: \" + err.Error())\n\t}\n\n\tif p.swagger.Info.Description == \"\" {\n\t\tt.Error(\"Failed to parse api description: \" + err.Error())\n\t}\n}\n\nfunc TestIgnoreInvalidPkg(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/deps_having_invalid_pkg\"\n\tp := New()\n\tif err := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth); err != nil {\n\t\tt.Error(\"Failed to ignore valid pkg: \" + err.Error())\n\t}\n}\n\nfunc TestFixes432(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/fixes-432\"\n\tmainAPIFile := \"cmd/main.go\"\n\n\tp := New()\n\tif err := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth); err != nil {\n\t\tt.Error(\"Failed to ignore valid pkg: \" + err.Error())\n\t}\n}\n\nfunc TestParseOutsideDependencies(t *testing.T) {\n\tt.Parallel()\n\n\tsearchDir := \"testdata/pare_outside_dependencies\"\n\tmainAPIFile := \"cmd/main.go\"\n\n\tp := New(SetParseDependency(1))\n\tif err := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth); err != nil {\n\t\tt.Error(\"Failed to parse api: \" + err.Error())\n\t}\n}\n\nfunc TestParseStructParamCommentByQueryType(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\n\ntype Student struct {\n\tName string\n\tAge int\n\tTeachers []string\n\tSkipField map[string]string\n}\n\n// @Param request query Student true \"query params\"\n// @Success 200\n// @Router /test [get]\nfunc Fun()  {\n\n}\n`\n\texpected := `{\n    \"info\": {\n        \"contact\": {}\n    },\n    \"paths\": {\n        \"/test\": {\n            \"get\": {\n                \"parameters\": [\n                    {\n                        \"type\": \"integer\",\n                        \"name\": \"age\",\n                        \"in\": \"query\"\n                    },\n                    {\n                        \"type\": \"string\",\n                        \"name\": \"name\",\n                        \"in\": \"query\"\n                    },\n                    {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        },\n                        \"name\": \"teachers\",\n                        \"in\": \"query\"\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\"\n                    }\n                }\n            }\n        }\n    }\n}`\n\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\t_, err = p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseStructParamCommentByQueryTypeWithQueryTag(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\n\ntype Student struct {\n\tProjectID int ` + \"`\" + `query:\"projectId\"` + \"`\" + `\n\tName      string ` + \"`\" + `query:\"name\"` + \"`\" + `\n\tSkipField string ` + \"`\" + `query:\"-\"` + \"`\" + `\n}\n\n// @Param request query Student true \"query params\"\n// @Success 200\n// @Router /test [get]\nfunc Fun()  {\n\n}\n`\n\texpected := `{\n    \"info\": {\n        \"contact\": {}\n    },\n    \"paths\": {\n        \"/test\": {\n            \"get\": {\n                \"parameters\": [\n                    {\n                        \"type\": \"string\",\n                        \"name\": \"name\",\n                        \"in\": \"query\"\n                    },\n                    {\n                        \"type\": \"integer\",\n                        \"name\": \"projectId\",\n                        \"in\": \"query\"\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\"\n                    }\n                }\n            }\n        }\n    }\n}`\n\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\t_, err = p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseParamCommentExtension(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\n\n// @Param request query string true \"query params\" extensions(x-example=[0, 9],x-foo=bar)\n// @Success 200\n// @Router /test [get]\nfunc Fun()  {\n\n}\n`\n\texpected := `{\n    \"info\": {\n        \"contact\": {}\n    },\n    \"paths\": {\n        \"/test\": {\n            \"get\": {\n                \"parameters\": [\n                    {\n                       \"type\": \"string\",\n                       \"x-example\": \"[0, 9]\",\n                       \"x-foo\": \"bar\",\n                       \"description\": \"query params\",\n                       \"name\": \"request\",\n                       \"in\": \"query\",\n                       \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\"\n                    }\n                }\n            }\n        }\n    }\n}`\n\n\tp := New()\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\n\t_, err := p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.JSONEq(t, expected, string(b))\n}\n\nfunc TestParseRenamedStructDefinition(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\n\ntype Child struct {\n\tName string\n}//@name Student\n\ntype Parent struct {\n\tName string\n\tChild Child\n}//@name Teacher\n\n// @Param request body Parent true \"query params\"\n// @Success 200 {object} Parent\n// @Router /test [get]\nfunc Fun()  {\n\n}\n`\n\n\tp := New()\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\t_, err := p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tassert.NoError(t, err)\n\tteacher, ok := p.swagger.Definitions[\"Teacher\"]\n\tassert.True(t, ok)\n\tref := teacher.Properties[\"child\"].SchemaProps.Ref\n\tassert.Equal(t, \"#/definitions/Student\", ref.String())\n\t_, ok = p.swagger.Definitions[\"Student\"]\n\tassert.True(t, ok)\n\tpath, ok := p.swagger.Paths.Paths[\"/test\"]\n\tassert.True(t, ok)\n\tassert.Equal(t, \"#/definitions/Teacher\", path.Get.Parameters[0].Schema.Ref.String())\n\tref = path.Get.Responses.ResponsesProps.StatusCodeResponses[200].ResponseProps.Schema.Ref\n\tassert.Equal(t, \"#/definitions/Teacher\", ref.String())\n}\n\nfunc TestParseTabFormattedRenamedStructDefinition(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := \"package main\\n\" +\n\t\t\"\\n\" +\n\t\t\"type Child struct {\\n\" +\n\t\t\"\\tName string\\n\" +\n\t\t\"}\\t//\\t@name\\tPupil\\n\" +\n\t\t\"\\n\" +\n\t\t\"// @Success 200 {object} Pupil\\n\" +\n\t\t\"func Fun()  { }\"\n\n\tp := New()\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\t_, err := p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\t_, ok := p.swagger.Definitions[\"Pupil\"]\n\tassert.True(t, ok)\n}\n\nfunc TestParseFunctionScopedStructDefinition(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\n\n// @Param request body main.Fun.request true \"query params\"\n// @Success 200 {object} main.Fun.response\n// @Router /test [post]\nfunc Fun()  {\n\ttype request struct {\n\t\tName string\n\t}\n\n\ttype response struct {\n\t\tName string\n\t\tChild string\n\t}\n}\n`\n\tp := New()\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\t_, err := p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\t_, ok := p.swagger.Definitions[\"main.Fun.response\"]\n\tassert.True(t, ok)\n}\n\nfunc TestParseFunctionScopedComplexStructDefinition(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\n\n// @Param request body main.Fun.request true \"query params\"\n// @Success 200 {object} main.Fun.response\n// @Router /test [post]\nfunc Fun()  {\n\ttype request struct {\n\t\tName string\n\t}\n\n\ttype grandChild struct {\n\t\tName string\n\t}\n\n\ttype pointerChild struct {\n\t\tName string\n\t}\n\n\ttype arrayChild struct {\n\t\tName string\n\t}\n\n\ttype child struct {\n\t\tGrandChild \t\tgrandChild\n\t\tPointerChild \t*pointerChild\n\t\tArrayChildren   []arrayChild\n\t}\n\n\ttype response struct {\n\t\tChildren \t[]child\n\t}\n}\n`\n\tp := New()\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\t_, err := p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\t_, ok := p.swagger.Definitions[\"main.Fun.response\"]\n\tassert.True(t, ok)\n\t_, ok = p.swagger.Definitions[\"main.Fun.child\"]\n\tassert.True(t, ok)\n\t_, ok = p.swagger.Definitions[\"main.Fun.grandChild\"]\n\tassert.True(t, ok)\n\t_, ok = p.swagger.Definitions[\"main.Fun.pointerChild\"]\n\tassert.True(t, ok)\n\t_, ok = p.swagger.Definitions[\"main.Fun.arrayChild\"]\n\tassert.True(t, ok)\n}\n\nfunc TestParseFunctionScopedStructRequestResponseJSON(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\n\n// @Param request body main.Fun.request true \"query params\"\n// @Success 200 {object} main.Fun.response\n// @Router /test [post]\nfunc Fun()  {\n\ttype request struct {\n\t\tName string\n\t}\n\n\ttype response struct {\n\t\tName string\n\t\tChild string\n\t}\n}\n`\n\texpected := `{\n    \"info\": {\n        \"contact\": {}\n    },\n    \"paths\": {\n        \"/test\": {\n            \"post\": {\n                \"parameters\": [\n                    {\n                        \"description\": \"query params\",\n                        \"name\": \"request\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/main.Fun.request\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/main.Fun.response\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"main.Fun.request\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"main.Fun.response\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"child\": {\n                    \"type\": \"string\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}`\n\n\tp := New()\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\n\t_, err := p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseFunctionScopedComplexStructRequestResponseJSON(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\n\ntype PublicChild struct {\n\tName string\n}\n\n// @Param request body main.Fun.request true \"query params\"\n// @Success 200 {object} main.Fun.response\n// @Router /test [post]\nfunc Fun()  {\n\ttype request struct {\n\t\tName string\n\t}\n\n\ttype grandChild struct {\n\t\tName string\n\t}\n\n\ttype child struct {\n\t\tGrandChild grandChild\n\t}\n\n\ttype response struct {\n\t\tChildren \t[]child\n\t    PublicChild PublicChild\n\t}\n}\n`\n\texpected := `{\n    \"info\": {\n        \"contact\": {}\n    },\n    \"paths\": {\n        \"/test\": {\n            \"post\": {\n                \"parameters\": [\n                    {\n                        \"description\": \"query params\",\n                        \"name\": \"request\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/main.Fun.request\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/main.Fun.response\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"main.Fun.child\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"grandChild\": {\n                    \"$ref\": \"#/definitions/main.Fun.grandChild\"\n                }\n            }\n        },\n        \"main.Fun.grandChild\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"main.Fun.request\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"main.Fun.response\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"children\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/main.Fun.child\"\n                    }\n                },\n                \"publicChild\": {\n                    \"$ref\": \"#/definitions/main.PublicChild\"\n                }\n            }\n        },\n        \"main.PublicChild\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}`\n\n\tp := New()\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\n\t_, err := p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestPackagesDefinitions_CollectAstFileInit(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\n\n// @Router /test [get]\nfunc Fun()  {\n\n}\n`\n\tpkgs := NewPackagesDefinitions()\n\n\t// unset the .files and .packages and check that they're re-initialized by collectAstFile\n\tpkgs.packages = nil\n\tpkgs.files = nil\n\n\t_ = pkgs.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NotNil(t, pkgs.packages)\n\tassert.NotNil(t, pkgs.files)\n}\n\nfunc TestCollectAstFileMultipleTimes(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\n\n// @Router /test [get]\nfunc Fun()  {\n\n}\n`\n\n\tp := New()\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.Equal(t, 1, len(p.packages.files))\n\tvar path string\n\tvar file *ast.File\n\tfor path, file = range p.packages.packages[\"api\"].Files {\n\t\tbreak\n\t}\n\tassert.NotNil(t, file)\n\tassert.NotNil(t, p.packages.files[file])\n\n\t// if we collect the same again nothing should happen\n\t_ = p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.Equal(t, 1, len(p.packages.files))\n\tassert.Equal(t, file, p.packages.packages[\"api\"].Files[path])\n\tassert.NotNil(t, p.packages.files[file])\n}\n\nfunc TestParseJSONFieldString(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:4000\",\n    \"basePath\": \"/\",\n    \"paths\": {\n        \"/do-something\": {\n            \"post\": {\n                \"description\": \"Does something\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Call DoSomething\",\n                \"parameters\": [\n                    {\n                        \"description\": \"My Struct\",\n                        \"name\": \"body\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/main.MyStruct\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/main.MyStruct\"\n                        }\n                    },\n                    \"500\": {\n                        \"description\": \"Internal Server Error\"\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"main.MyStruct\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"boolvar\": {\n                    \"description\": \"boolean as a string\",\n                    \"type\": \"string\",\n                    \"example\": \"false\"\n                },\n                \"floatvar\": {\n                    \"description\": \"float as a string\",\n                    \"type\": \"string\",\n                    \"example\": \"0\"\n                },\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\",\n                    \"example\": 1\n                },\n                \"myint\": {\n                    \"description\": \"integer as string\",\n                    \"type\": \"string\",\n                    \"example\": \"0\"\n                },\n                \"name\": {\n                    \"type\": \"string\",\n                    \"example\": \"poti\"\n                },\n                \"truebool\": {\n                    \"description\": \"boolean as a string\",\n                    \"type\": \"string\",\n                    \"example\": \"true\"\n                },\n                \"uuids\": {\n                    \"description\": \"string array with format\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\",\n                        \"format\": \"uuid\"\n                    }\n                }\n            }\n        }\n    }\n}`\n\n\tsearchDir := \"testdata/json_field_string\"\n\tp := New()\n\terr := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\tb, _ := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.Equal(t, expected, string(b))\n}\n\nfunc TestParseSwaggerignoreForEmbedded(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\n\ntype Child struct {\n\tChildName string\n}//@name Student\n\ntype Parent struct {\n\tName string\n\tChild ` + \"`swaggerignore:\\\"true\\\"`\" + `\n}//@name Teacher\n\n// @Param request body Parent true \"query params\"\n// @Success 200 {object} Parent\n// @Router /test [get]\nfunc Fun()  {\n\n}\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\t_, _ = p.packages.ParseTypes()\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tteacher, ok := p.swagger.Definitions[\"Teacher\"]\n\tassert.True(t, ok)\n\n\tname, ok := teacher.Properties[\"name\"]\n\tassert.True(t, ok)\n\tassert.Len(t, name.Type, 1)\n\tassert.Equal(t, \"string\", name.Type[0])\n\n\tchildName, ok := teacher.Properties[\"childName\"]\n\tassert.False(t, ok)\n\tassert.Empty(t, childName)\n}\n\nfunc TestDefineTypeOfExample(t *testing.T) {\n\n\tt.Run(\"String type\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texample, err := defineTypeOfExample(\"string\", \"\", \"example\")\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, example.(string), \"example\")\n\t})\n\n\tt.Run(\"Number type\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texample, err := defineTypeOfExample(\"number\", \"\", \"12.34\")\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, example.(float64), 12.34)\n\n\t\t_, err = defineTypeOfExample(\"number\", \"\", \"two\")\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"Integer type\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texample, err := defineTypeOfExample(\"integer\", \"\", \"12\")\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, example.(int), 12)\n\n\t\t_, err = defineTypeOfExample(\"integer\", \"\", \"two\")\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"Boolean type\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texample, err := defineTypeOfExample(\"boolean\", \"\", \"true\")\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, example.(bool), true)\n\n\t\t_, err = defineTypeOfExample(\"boolean\", \"\", \"!true\")\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"Array type\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texample, err := defineTypeOfExample(\"array\", \"\", \"one,two,three\")\n\t\tassert.Error(t, err)\n\t\tassert.Nil(t, example)\n\n\t\texample, err = defineTypeOfExample(\"array\", \"string\", \"one,two,three\")\n\t\tassert.NoError(t, err)\n\n\t\tvar arr []string\n\n\t\tfor _, v := range example.([]interface{}) {\n\t\t\tarr = append(arr, v.(string))\n\t\t}\n\n\t\tassert.Equal(t, arr, []string{\"one\", \"two\", \"three\"})\n\t})\n\n\tt.Run(\"Object type\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texample, err := defineTypeOfExample(\"object\", \"\", \"key_one:one,key_two:two,key_three:three\")\n\t\tassert.Error(t, err)\n\t\tassert.Nil(t, example)\n\n\t\texample, err = defineTypeOfExample(\"object\", \"string\", \"key_one,key_two,key_three\")\n\t\tassert.Error(t, err)\n\t\tassert.Nil(t, example)\n\n\t\texample, err = defineTypeOfExample(\"object\", \"oops\", \"key_one:one,key_two:two,key_three:three\")\n\t\tassert.Error(t, err)\n\t\tassert.Nil(t, example)\n\n\t\texample, err = defineTypeOfExample(\"object\", \"string\", \"key_one:one,key_two:two,key_three:three\")\n\t\tassert.NoError(t, err)\n\t\tobj := map[string]string{}\n\n\t\tfor k, v := range example.(map[string]interface{}) {\n\t\t\tobj[k] = v.(string)\n\t\t}\n\n\t\tassert.Equal(t, obj, map[string]string{\"key_one\": \"one\", \"key_two\": \"two\", \"key_three\": \"three\"})\n\t})\n\n\tt.Run(\"Invalid type\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texample, err := defineTypeOfExample(\"oops\", \"\", \"\")\n\t\tassert.Error(t, err)\n\t\tassert.Nil(t, example)\n\t})\n}\n\ntype mockFS struct {\n\tos.FileInfo\n\tFileName    string\n\tIsDirectory bool\n}\n\nfunc (fs *mockFS) Name() string {\n\treturn fs.FileName\n}\n\nfunc (fs *mockFS) IsDir() bool {\n\treturn fs.IsDirectory\n}\n\nfunc TestParser_Skip(t *testing.T) {\n\tt.Parallel()\n\n\tparser := New()\n\tparser.ParseVendor = true\n\n\tassert.NoError(t, parser.Skip(\"\", &mockFS{FileName: \"vendor\"}))\n\tassert.NoError(t, parser.Skip(\"\", &mockFS{FileName: \"vendor\", IsDirectory: true}))\n\n\tparser.ParseVendor = false\n\tassert.NoError(t, parser.Skip(\"\", &mockFS{FileName: \"vendor\"}))\n\tassert.Error(t, parser.Skip(\"\", &mockFS{FileName: \"vendor\", IsDirectory: true}))\n\n\tassert.NoError(t, parser.Skip(\"\", &mockFS{FileName: \"models\", IsDirectory: true}))\n\tassert.NoError(t, parser.Skip(\"\", &mockFS{FileName: \"admin\", IsDirectory: true}))\n\tassert.NoError(t, parser.Skip(\"\", &mockFS{FileName: \"release\", IsDirectory: true}))\n\tassert.NoError(t, parser.Skip(\"\", &mockFS{FileName: \"..\", IsDirectory: true}))\n\n\tparser = New(SetExcludedDirsAndFiles(\"admin/release,admin/models\"))\n\tassert.NoError(t, parser.Skip(\"admin\", &mockFS{IsDirectory: true}))\n\tassert.NoError(t, parser.Skip(filepath.Clean(\"admin/service\"), &mockFS{IsDirectory: true}))\n\tassert.Error(t, parser.Skip(filepath.Clean(\"admin/models\"), &mockFS{IsDirectory: true}))\n\tassert.Error(t, parser.Skip(filepath.Clean(\"admin/release\"), &mockFS{IsDirectory: true}))\n}\n\nfunc TestGetFuncDoc_NilPointerSafety(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\tdecl     interface{}\n\t\twantDoc  *ast.CommentGroup\n\t\twantBool bool\n\t}{\n\t\t{\n\t\t\tname: \"GenDecl with empty Specs\",\n\t\t\tdecl: &ast.GenDecl{\n\t\t\t\tTok:   token.VAR,\n\t\t\t\tSpecs: []ast.Spec{}, // empty specs\n\t\t\t},\n\t\t\twantDoc:  nil,\n\t\t\twantBool: false,\n\t\t},\n\t\t{\n\t\t\tname: \"ValueSpec with empty Values\",\n\t\t\tdecl: &ast.ValueSpec{\n\t\t\t\tValues: []ast.Expr{}, // empty values\n\t\t\t},\n\t\t\twantDoc:  nil,\n\t\t\twantBool: false,\n\t\t},\n\t\t{\n\t\t\tname: \"ValueSpec with nil Obj\",\n\t\t\tdecl: &ast.ValueSpec{\n\t\t\t\tValues: []ast.Expr{\n\t\t\t\t\t&ast.Ident{\n\t\t\t\t\t\tName: \"test\",\n\t\t\t\t\t\tObj:  nil, // nil object\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantDoc:  nil,\n\t\t\twantBool: false,\n\t\t},\n\t\t{\n\t\t\tname: \"ValueSpec with nil Obj.Decl\",\n\t\t\tdecl: &ast.ValueSpec{\n\t\t\t\tValues: []ast.Expr{\n\t\t\t\t\t&ast.Ident{\n\t\t\t\t\t\tName: \"test\",\n\t\t\t\t\t\tObj: &ast.Object{\n\t\t\t\t\t\t\tDecl: nil, // nil declaration\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantDoc:  nil,\n\t\t\twantBool: false,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\ttt := tt\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tgotDoc, gotBool := getFuncDoc(tt.decl)\n\t\t\tassert.Equal(t, tt.wantDoc, gotDoc)\n\t\t\tassert.Equal(t, tt.wantBool, gotBool)\n\t\t})\n\t}\n}\n\nfunc TestGetFieldType(t *testing.T) {\n\tt.Parallel()\n\n\tfield, err := getFieldType(&ast.File{}, &ast.Ident{Name: \"User\"}, nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"User\", field)\n\n\t_, err = getFieldType(&ast.File{}, &ast.FuncType{}, nil)\n\tassert.Error(t, err)\n\n\tfield, err = getFieldType(&ast.File{}, &ast.SelectorExpr{X: &ast.Ident{Name: \"models\"}, Sel: &ast.Ident{Name: \"User\"}}, nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"models.User\", field)\n\n\t_, err = getFieldType(&ast.File{}, &ast.SelectorExpr{X: &ast.FuncType{}, Sel: &ast.Ident{Name: \"User\"}}, nil)\n\tassert.Error(t, err)\n\n\tfield, err = getFieldType(&ast.File{}, &ast.StarExpr{X: &ast.Ident{Name: \"User\"}}, nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"User\", field)\n\n\tfield, err = getFieldType(&ast.File{}, &ast.StarExpr{X: &ast.FuncType{}}, nil)\n\tassert.Error(t, err)\n\n\tfield, err = getFieldType(&ast.File{}, &ast.StarExpr{X: &ast.SelectorExpr{X: &ast.Ident{Name: \"models\"}, Sel: &ast.Ident{Name: \"User\"}}}, nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"models.User\", field)\n}\n\nfunc TestTryAddDescription(t *testing.T) {\n\ttype args struct {\n\t\tspec       *spec.SecurityScheme\n\t\textensions map[string]interface{}\n\t}\n\ttests := []struct {\n\t\tname  string\n\t\tlines []string\n\t\targs  args\n\t\twant  *spec.SecurityScheme\n\t}{\n\t\t{\n\t\t\tname: \"added description\",\n\t\t\tlines: []string{\n\t\t\t\t\"\\t@securitydefinitions.apikey test\",\n\t\t\t\t\"\\t@in header\",\n\t\t\t\t\"\\t@name x-api-key\",\n\t\t\t\t\"\\t@description some description\",\n\t\t\t},\n\t\t\twant: &spec.SecurityScheme{\n\t\t\t\tSecuritySchemeProps: spec.SecuritySchemeProps{\n\t\t\t\t\tName:        \"x-api-key\",\n\t\t\t\t\tType:        \"apiKey\",\n\t\t\t\t\tIn:          \"header\",\n\t\t\t\t\tDescription: \"some description\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"added description with multiline\",\n\t\t\tlines: []string{\n\t\t\t\t\"\\t@securitydefinitions.apikey test\",\n\t\t\t\t\"\\t@in header\",\n\t\t\t\t\"\\t@name x-api-key\",\n\t\t\t\t\"\\t@description line1\",\n\t\t\t\t\"\\t@description line2\",\n\t\t\t},\n\t\t\twant: &spec.SecurityScheme{\n\t\t\t\tSecuritySchemeProps: spec.SecuritySchemeProps{\n\t\t\t\t\tName:        \"x-api-key\",\n\t\t\t\t\tType:        \"apiKey\",\n\t\t\t\t\tIn:          \"header\",\n\t\t\t\t\tDescription: \"line1\\nline2\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"no description\",\n\t\t\tlines: []string{\n\t\t\t\t\" @securitydefinitions.oauth2.application swagger\",\n\t\t\t\t\" @tokenurl https://example.com/oauth/token\",\n\t\t\t\t\" @not-description some description\",\n\t\t\t},\n\t\t\twant: &spec.SecurityScheme{\n\t\t\t\tSecuritySchemeProps: spec.SecuritySchemeProps{\n\t\t\t\t\tType:        \"oauth2\",\n\t\t\t\t\tFlow:        \"application\",\n\t\t\t\t\tTokenURL:    \"https://example.com/oauth/token\",\n\t\t\t\t\tDescription: \"\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\n\t\t{\n\t\t\tname: \"description has invalid format\",\n\t\t\tlines: []string{\n\t\t\t\t\"@securitydefinitions.oauth2.implicit swagger\",\n\t\t\t\t\"@authorizationurl https://example.com/oauth/token\",\n\t\t\t\t\"@description 12345\",\n\t\t\t},\n\n\t\t\twant: &spec.SecurityScheme{\n\t\t\t\tSecuritySchemeProps: spec.SecuritySchemeProps{\n\t\t\t\t\tType:             \"oauth2\",\n\t\t\t\t\tFlow:             \"implicit\",\n\t\t\t\t\tAuthorizationURL: \"https://example.com/oauth/token\",\n\t\t\t\t\tDescription:      \"12345\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tswag := spec.Swagger{\n\t\t\t\tSwaggerProps: spec.SwaggerProps{\n\t\t\t\t\tSecurityDefinitions: make(map[string]*spec.SecurityScheme),\n\t\t\t\t},\n\t\t\t}\n\t\t\tline := 0\n\t\t\tcommentLine := tt.lines[line]\n\t\t\tattribute := strings.Split(commentLine, \" \")[0]\n\t\t\tvalue := strings.TrimSpace(commentLine[len(attribute):])\n\t\t\tsecAttr, _ := parseSecAttributes(attribute, tt.lines, &line)\n\t\t\tif !reflect.DeepEqual(secAttr, tt.want) {\n\t\t\t\tt.Errorf(\"setSwaggerSecurity() = %#v, want %#v\", swag.SecurityDefinitions[value], tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_getTagsFromComment(t *testing.T) {\n\ttype args struct {\n\t\tcomment string\n\t}\n\ttests := []struct {\n\t\tname     string\n\t\targs     args\n\t\twantTags []string\n\t}{\n\t\t{\n\t\t\tname: \"no tags comment\",\n\t\t\targs: args{\n\t\t\t\tcomment: \"//@name Student\",\n\t\t\t},\n\t\t\twantTags: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"empty comment\",\n\t\t\targs: args{\n\t\t\t\tcomment: \"//\",\n\t\t\t},\n\t\t\twantTags: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"tags comment\",\n\t\t\targs: args{\n\t\t\t\tcomment: \"//@Tags tag1,tag2,tag3\",\n\t\t\t},\n\t\t\twantTags: []string{\"tag1\", \"tag2\", \"tag3\"},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif gotTags := getTagsFromComment(tt.args.comment); !reflect.DeepEqual(gotTags, tt.wantTags) {\n\t\t\t\tt.Errorf(\"getTagsFromComment() = %v, want %v\", gotTags, tt.wantTags)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParser_matchTags(t *testing.T) {\n\n\ttype args struct {\n\t\tcomments []*ast.Comment\n\t}\n\ttests := []struct {\n\t\tname      string\n\t\tparser    *Parser\n\t\targs      args\n\t\twantMatch bool\n\t}{\n\t\t{\n\t\t\tname:      \"no tags filter\",\n\t\t\tparser:    New(),\n\t\t\targs:      args{comments: []*ast.Comment{{Text: \"//@Tags tag1,tag2,tag3\"}}},\n\t\t\twantMatch: true,\n\t\t},\n\t\t{\n\t\t\tname:      \"with tags filter but no match\",\n\t\t\tparser:    New(SetTags(\"tag4,tag5,!tag1\")),\n\t\t\targs:      args{comments: []*ast.Comment{{Text: \"//@Tags tag1,tag2,tag3\"}}},\n\t\t\twantMatch: false,\n\t\t},\n\t\t{\n\t\t\tname:      \"with tags filter but match\",\n\t\t\tparser:    New(SetTags(\"tag4,tag5,tag1\")),\n\t\t\targs:      args{comments: []*ast.Comment{{Text: \"//@Tags tag1,tag2,tag3\"}}},\n\t\t\twantMatch: true,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif gotMatch := tt.parser.matchTags(tt.args.comments); gotMatch != tt.wantMatch {\n\t\t\t\tt.Errorf(\"Parser.matchTags() = %v, want %v\", gotMatch, tt.wantMatch)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParser_parseExtension(t *testing.T) {\n\tpackagePath := \"testdata/parseExtension\"\n\tfilePath := packagePath + \"/parseExtension.go\"\n\tsrc, err := os.ReadFile(filePath)\n\tassert.NoError(t, err)\n\n\tfileSet := token.NewFileSet()\n\tf, err := goparser.ParseFile(fileSet, \"\", src, goparser.ParseComments)\n\tassert.NoError(t, err)\n\n\ttests := []struct {\n\t\tname          string\n\t\tparser        *Parser\n\t\texpectedPaths map[string]bool\n\t}{\n\t\t{\n\t\t\tname:          \"when no flag is set, everything is exported\",\n\t\t\tparser:        New(),\n\t\t\texpectedPaths: map[string]bool{\"/without-extension\": true, \"/with-another-extension\": true, \"/with-correct-extension\": true, \"/with-empty-comment-line\": true},\n\t\t},\n\t\t{\n\t\t\tname:          \"when nonexistent flag is set, nothing is exported\",\n\t\t\tparser:        New(SetParseExtension(\"nonexistent-extension-filter\")),\n\t\t\texpectedPaths: map[string]bool{\"/without-extension\": false, \"/with-another-extension\": false, \"/with-correct-extension\": false, \"/with-empty-comment-line\": false},\n\t\t},\n\t\t{\n\t\t\tname:          \"when correct flag is set, only that Path is exported\",\n\t\t\tparser:        New(SetParseExtension(\"google-backend\")),\n\t\t\texpectedPaths: map[string]bool{\"/without-extension\": false, \"/with-another-extension\": false, \"/with-correct-extension\": true, \"/with-empty-comment-line\": false},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr = tt.parser.ParseRouterAPIInfo(&AstFileInfo{\n\t\t\t\tFileSet:     fileSet,\n\t\t\t\tFile:        f,\n\t\t\t\tPath:        filePath,\n\t\t\t\tPackagePath: packagePath,\n\t\t\t\tParseFlag:   ParseAll,\n\t\t\t})\n\t\t\tassert.NoError(t, err)\n\t\t\tfor p, isExpected := range tt.expectedPaths {\n\t\t\t\t_, ok := tt.parser.swagger.Paths.Paths[p]\n\t\t\t\tassert.Equal(t, isExpected, ok)\n\t\t\t}\n\n\t\t\tfor p := range tt.parser.swagger.Paths.Paths {\n\t\t\t\t_, isExpected := tt.expectedPaths[p]\n\t\t\t\tassert.Equal(t, isExpected, true)\n\t\t\t}\n\t\t})\n\n\t}\n}\n\nfunc TestParser_collectionFormat(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tparser *Parser\n\t\tformat string\n\t}{\n\t\t{\n\t\t\tname:   \"no collectionFormat\",\n\t\t\tparser: New(),\n\t\t\tformat: \"\",\n\t\t},\n\t\t{\n\t\t\tname:   \"multi collectionFormat\",\n\t\t\tparser: New(SetCollectionFormat(\"multi\")),\n\t\t\tformat: \"multi\",\n\t\t},\n\t\t{\n\t\t\tname:   \"ssv collectionFormat\",\n\t\t\tparser: New(SetCollectionFormat(\"ssv\")),\n\t\t\tformat: \"ssv\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif tt.parser.collectionFormatInQuery != tt.format {\n\t\t\t\tt.Errorf(\"Parser.collectionFormatInQuery = %s, want %s\", tt.parser.collectionFormatInQuery, tt.format)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParser_skipPackageByPrefix(t *testing.T) {\n\tt.Parallel()\n\n\tparser := New()\n\n\tassert.False(t, parser.skipPackageByPrefix(\"github.com/swaggo/swag\"))\n\tassert.False(t, parser.skipPackageByPrefix(\"github.com/swaggo/swag/cmd\"))\n\tassert.False(t, parser.skipPackageByPrefix(\"github.com/swaggo/swag/gen\"))\n\n\tparser = New(SetPackagePrefix(\"github.com/swaggo/swag/cmd\"))\n\n\tassert.True(t, parser.skipPackageByPrefix(\"github.com/swaggo/swag\"))\n\tassert.False(t, parser.skipPackageByPrefix(\"github.com/swaggo/swag/cmd\"))\n\tassert.True(t, parser.skipPackageByPrefix(\"github.com/swaggo/swag/gen\"))\n\n\tparser = New(SetPackagePrefix(\"github.com/swaggo/swag/cmd,github.com/swaggo/swag/gen\"))\n\n\tassert.True(t, parser.skipPackageByPrefix(\"github.com/swaggo/swag\"))\n\tassert.False(t, parser.skipPackageByPrefix(\"github.com/swaggo/swag/cmd\"))\n\tassert.False(t, parser.skipPackageByPrefix(\"github.com/swaggo/swag/gen\"))\n}\n\nfunc TestParser_ParseRouterApiInFuncBody(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\nfunc Test(){\n    // @Router /api/{id} [get]\n    _ = func() {\n\t}\n}\n`\n\tp := New()\n\tp.ParseFuncBody = true\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tps := p.swagger.Paths.Paths\n\n\tval, ok := ps[\"/api/{id}\"]\n\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Get)\n}\n\nfunc TestParser_ParseRouterApiInfoInAndOutFuncBody(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage test\n\n// @Router /api/outside [get]\nfunc otherRoute(){\n}\n\nfunc Test(){\n    // @Router /api/inside [get]\n    _ = func() {\n\t}\n}\n`\n\tp := New()\n\tp.ParseFuncBody = true\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tps := p.swagger.Paths.Paths\n\n\tval1, ok := ps[\"/api/outside\"]\n\tassert.True(t, ok)\n\tassert.NotNil(t, val1.Get)\n\n\tval2, ok := ps[\"/api/inside\"]\n\tassert.True(t, ok)\n\tassert.NotNil(t, val2.Get)\n}\n\nfunc TestParser_EmbeddedStructAsOtherAliasGoListNested(t *testing.T) {\n\tt.Parallel()\n\n\tp := New(SetParseDependency(1), ParseUsingGoList(true))\n\n\tp.parseGoList = true\n\n\tsearchDir := \"testdata/alias_nested\"\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\terr = p.ParseAPI(searchDir, \"cmd/main/main.go\", 0)\n\tassert.NoError(t, err)\n\n\tb, err := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\nfunc TestParser_genVarDefinedFuncDoc(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `\npackage main\nfunc f() {}\n// @Summary\tgenerate var-defined functions' doc\n// @Router /test [get]\nvar Func = f\n// @Summary generate indirectly pointing\n// @Router /test2 [get]\nvar Func2 = Func\n`\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/api.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\t_, _ = p.packages.ParseTypes()\n\terr = p.packages.RangeFiles(p.ParseRouterAPIInfo)\n\tassert.NoError(t, err)\n\n\tval, ok := p.swagger.Paths.Paths[\"/test\"]\n\tassert.True(t, ok)\n\tassert.NotNil(t, val.Get)\n\tassert.Equal(t, val.Get.OperationProps.Summary, \"generate var-defined functions' doc\")\n\n\tval2, ok := p.swagger.Paths.Paths[\"/test2\"]\n\tassert.True(t, ok)\n\tassert.NotNil(t, val2.Get)\n\tassert.Equal(t, val2.Get.OperationProps.Summary, \"generate indirectly pointing\")\n}\n\nfunc TestParser_DescriptionLineContinuation(t *testing.T) {\n\tt.Parallel()\n\n\tp := New()\n\tsearchDir := \"testdata/description_line_continuation\"\n\texpected, err := os.ReadFile(filepath.Join(searchDir, \"expected.json\"))\n\tassert.NoError(t, err)\n\n\terr = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)\n\tassert.NoError(t, err)\n\n\tb, err := json.MarshalIndent(p.swagger, \"\", \"    \")\n\tassert.NoError(t, err)\n\tassert.Equal(t, string(expected), string(b))\n}\n\n// TestParser_ParseDefinitionWithRecursiveTypeAndNameAnnotation tests that @name annotations\n// are properly respected for recursive types\nfunc TestParser_ParseDefinitionWithRecursiveTypeAndNameAnnotation(t *testing.T) {\n\tsrc := `package api\n\n// TreeNode represents a node in a tree structure\ntype TreeNode struct {\n\tValue    string     ` + \"`json:\\\"value\\\"`\" + `\n\tChildren []TreeNode ` + \"`json:\\\"children\\\"`\" + `\n} // @name TreeNode\n\n// LinkedNode represents a node in a linked structure\ntype LinkedNode struct {\n\tData string       ` + \"`json:\\\"data\\\"`\" + `\n\tNext *LinkedNode  ` + \"`json:\\\"next\\\"`\" + `\n} // @name CustomLinkedNode\n`\n\n\tp := New()\n\terr := p.packages.ParseFile(\"api\", \"api/tree.go\", src, ParseAll)\n\tassert.NoError(t, err)\n\n\t_, err = p.packages.ParseTypes()\n\tassert.NoError(t, err)\n\n\t// Find the TreeNode type\n\ttreeNodeDef := p.packages.FindTypeSpec(\"api.TreeNode\", nil)\n\tassert.NotNil(t, treeNodeDef)\n\n\t// Parse the TreeNode definition\n\tschema, err := p.ParseDefinition(treeNodeDef)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, schema)\n\tassert.Equal(t, \"TreeNode\", schema.Name) // Should use @name annotation\n\n\t// Find the LinkedNode type\n\tlinkedNodeDef := p.packages.FindTypeSpec(\"api.LinkedNode\", nil)\n\tassert.NotNil(t, linkedNodeDef)\n\n\t// Parse the LinkedNode definition\n\tschema2, err := p.ParseDefinition(linkedNodeDef)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, schema2)\n\tassert.Equal(t, \"CustomLinkedNode\", schema2.Name) // Should use @name annotation\n\n\t// Verify the definitions were added to swagger with correct names\n\tassert.NotNil(t, p.swagger.Definitions[\"TreeNode\"])\n\tassert.NotNil(t, p.swagger.Definitions[\"CustomLinkedNode\"])\n\n\t// The fix is working if the definitions use the @name annotation\n\t// TreeNode should be \"TreeNode\", not \"api.TreeNode\"\n\t// LinkedNode should be \"CustomLinkedNode\", not \"api.LinkedNode\"\n\tfor name := range p.swagger.Definitions {\n\t\t// Ensure no definitions use the full package path format\n\t\tassert.NotContains(t, name, \"api.TreeNode\")\n\t\tassert.NotContains(t, name, \"api.LinkedNode\")\n\t}\n}\n"
  },
  {
    "path": "parsergopackages.go",
    "content": "package swag\n\nimport (\n\t\"go/token\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\n\t\"golang.org/x/tools/go/packages\"\n)\n\nfunc (parser *Parser) loadPackagesAndDeps(searchDirs []string, absMainAPIFilePath string) error {\n\tmode := packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports |\n\t\tpackages.NeedTypes | packages.NeedTypesSizes | packages.NeedSyntax | packages.NeedTypesInfo\n\tif parser.ParseDependency > 0 {\n\t\tmode |= packages.NeedDeps\n\t}\n\n\tabsDirs := make([]string, 0, len(searchDirs)+1)\n\tabsDirs = append(absDirs, filepath.Dir(absMainAPIFilePath))\n\tfor _, dir := range searchDirs {\n\t\tabsDir, err := filepath.Abs(dir)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// load all subpackages keep the same logic with Parser.getAllGoFileInfo\n\t\tabsDirs = append(absDirs, absDir+\"/...\")\n\t}\n\n\tfset := token.NewFileSet()\n\tpkgs, err := packages.Load(&packages.Config{\n\t\tMode: mode,\n\t\tFset: fset,\n\t}, absDirs...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, pkg := range pkgs {\n\t\tfor _, e := range pkg.Errors {\n\t\t\treturn e\n\t\t}\n\t}\n\n\terr = parser.walkPackages(pkgs, func(pkg *packages.Package) error {\n\t\tparseFlag := ParseFlag(ParseAll)\n\t\tif !slices.Contains(pkgs, pkg) {\n\t\t\tparseFlag = parser.ParseDependency\n\t\t}\n\t\tfor i, file := range pkg.CompiledGoFiles {\n\t\t\t// TODO handle vendor?\n\t\t\tfileInfo, err := os.Stat(file)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif parser.Skip(file, fileInfo) != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif err = parser.packages.CollectAstFile(fset, pkg.PkgPath, file, pkg.Syntax[i], parseFlag); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n\n\tparser.packages.AddPackages(pkgs)\n\treturn err\n}\n\nfunc (parser *Parser) walkPackages(pkgs []*packages.Package, f func(p *packages.Package) error) error {\n\tpkgSeen := make(map[string]struct{})\n\treturn parser.walkPackagesInternal(pkgs, f, pkgSeen)\n}\n\nfunc (parser *Parser) walkPackagesInternal(pkgs []*packages.Package, f func(p *packages.Package) error,\n\tpkgSeen map[string]struct{}) error {\n\tfor _, pkg := range pkgs {\n\t\tif parser.skipPackageByPrefix(pkg.PkgPath) {\n\t\t\tcontinue\n\t\t}\n\t\tif _, ok := pkgSeen[pkg.PkgPath]; ok {\n\t\t\tcontinue\n\t\t}\n\t\tpkgSeen[pkg.PkgPath] = struct{}{}\n\n\t\tif err := f(pkg); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif parser.ParseDependency > 0 {\n\t\t\timports := make([]*packages.Package, 0, len(pkg.Imports))\n\t\t\tfor _, dep := range pkg.Imports {\n\t\t\t\timports = append(imports, dep)\n\t\t\t}\n\t\t\tif err := parser.walkPackagesInternal(imports, f, pkgSeen); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "schema.go",
    "content": "package swag\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/go-openapi/spec\"\n\t\"go/ast\"\n\t\"regexp\"\n\t\"strings\"\n)\n\nconst (\n\t// ARRAY represent a array value.\n\tARRAY = \"array\"\n\t// OBJECT represent a object value.\n\tOBJECT = \"object\"\n\t// PRIMITIVE represent a primitive value.\n\tPRIMITIVE = \"primitive\"\n\t// BOOLEAN represent a boolean value.\n\tBOOLEAN = \"boolean\"\n\t// INTEGER represent a integer value.\n\tINTEGER = \"integer\"\n\t// NUMBER represent a number value.\n\tNUMBER = \"number\"\n\t// STRING represent a string value.\n\tSTRING = \"string\"\n\t// FUNC represent a function value.\n\tFUNC = \"func\"\n\t// ERROR represent a error value.\n\tERROR = \"error\"\n\t// INTERFACE represent a interface value.\n\tINTERFACE = \"interface{}\"\n\t// ANY represent a any value.\n\tANY = \"any\"\n\t// NIL represent a empty value.\n\tNIL = \"nil\"\n\n\t// IgnoreNameOverridePrefix Prepend to model to avoid renaming based on comment.\n\tIgnoreNameOverridePrefix = '$'\n)\n\n// CheckSchemaType checks if typeName is not a name of primitive type.\nfunc CheckSchemaType(typeName string) error {\n\tif !IsPrimitiveType(typeName) {\n\t\treturn fmt.Errorf(\"%s is not basic types\", typeName)\n\t}\n\n\treturn nil\n}\n\n// IsSimplePrimitiveType determine whether the type name is a simple primitive type.\nfunc IsSimplePrimitiveType(typeName string) bool {\n\tswitch typeName {\n\tcase STRING, NUMBER, INTEGER, BOOLEAN:\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// IsPrimitiveType determine whether the type name is a primitive type.\nfunc IsPrimitiveType(typeName string) bool {\n\tswitch typeName {\n\tcase STRING, NUMBER, INTEGER, BOOLEAN, ARRAY, OBJECT, FUNC:\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// IsInterfaceLike determines whether the swagger type name is an go named interface type like error type.\nfunc IsInterfaceLike(typeName string) bool {\n\treturn typeName == ERROR || typeName == ANY\n}\n\n// IsNumericType determines whether the swagger type name is a numeric type.\nfunc IsNumericType(typeName string) bool {\n\treturn typeName == INTEGER || typeName == NUMBER\n}\n\n// TransToValidPrimitiveSchema transfer golang basic type to swagger schema with format considered.\nfunc TransToValidPrimitiveSchema(typeName string) *spec.Schema {\n\tswitch typeName {\n\tcase \"int\", \"uint\":\n\t\treturn &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{INTEGER}}}\n\tcase \"uint8\", \"int8\", \"uint16\", \"int16\", \"byte\", \"int32\", \"uint32\", \"rune\":\n\t\treturn &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{INTEGER}, Format: \"int32\"}}\n\tcase \"uint64\", \"int64\":\n\t\treturn &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{INTEGER}, Format: \"int64\"}}\n\tcase \"float32\", \"float64\":\n\t\treturn &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{NUMBER}, Format: typeName}}\n\tcase \"bool\":\n\t\treturn &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{BOOLEAN}}}\n\tcase \"string\":\n\t\treturn &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{STRING}}}\n\t}\n\treturn &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{typeName}}}\n}\n\n// TransToValidSchemeTypeWithFormat indicates type will transfer golang basic type to swagger supported type with format.\nfunc TransToValidSchemeTypeWithFormat(typeName string) (string, string) {\n\tswitch typeName {\n\tcase \"int\", \"uint\":\n\t\treturn INTEGER, \"\"\n\tcase \"uint8\", \"int8\", \"uint16\", \"int16\", \"byte\", \"int32\", \"uint32\", \"rune\":\n\t\treturn INTEGER, \"int32\"\n\tcase \"uint64\", \"int64\":\n\t\treturn INTEGER, \"int64\"\n\tcase \"float32\", \"float64\":\n\t\treturn NUMBER, typeName\n\tcase \"bool\":\n\t\treturn BOOLEAN, \"\"\n\tcase \"string\":\n\t\treturn STRING, \"\"\n\t}\n\treturn typeName, \"\"\n}\n\n// TransToValidSchemeType indicates type will transfer golang basic type to swagger supported type.\nfunc TransToValidSchemeType(typeName string) string {\n\tswitch typeName {\n\tcase \"uint\", \"int\", \"uint8\", \"int8\", \"uint16\", \"int16\", \"byte\":\n\t\treturn INTEGER\n\tcase \"uint32\", \"int32\", \"rune\":\n\t\treturn INTEGER\n\tcase \"uint64\", \"int64\":\n\t\treturn INTEGER\n\tcase \"float32\", \"float64\":\n\t\treturn NUMBER\n\tcase \"bool\":\n\t\treturn BOOLEAN\n\tcase \"string\":\n\t\treturn STRING\n\t}\n\n\treturn typeName\n}\n\n// IsGolangPrimitiveType determine whether the type name is a golang primitive type.\nfunc IsGolangPrimitiveType(typeName string) bool {\n\tswitch typeName {\n\tcase \"uint\",\n\t\t\"int\",\n\t\t\"uint8\",\n\t\t\"int8\",\n\t\t\"uint16\",\n\t\t\"int16\",\n\t\t\"byte\",\n\t\t\"uint32\",\n\t\t\"int32\",\n\t\t\"rune\",\n\t\t\"uint64\",\n\t\t\"int64\",\n\t\t\"float32\",\n\t\t\"float64\",\n\t\t\"bool\",\n\t\t\"string\":\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// TransToValidCollectionFormat determine valid collection format.\nfunc TransToValidCollectionFormat(format string) string {\n\tswitch format {\n\tcase \"csv\", \"multi\", \"pipes\", \"tsv\", \"ssv\":\n\t\treturn format\n\t}\n\n\treturn \"\"\n}\n\nfunc ignoreNameOverride(name string) bool {\n\treturn len(name) != 0 && name[0] == IgnoreNameOverridePrefix\n}\n\nvar overrideNameRegex = regexp.MustCompile(`(?i)^@name\\s+(\\S+)`)\n\nfunc nameOverride(commentGroup *ast.CommentGroup) string {\n\tif commentGroup == nil {\n\t\treturn \"\"\n\t}\n\n\t// get alias from comment '// @name '\n\tfor _, comment := range commentGroup.List {\n\t\ttrimmedComment := strings.TrimSpace(strings.TrimLeft(comment.Text, \"/\"))\n\t\ttexts := overrideNameRegex.FindStringSubmatch(trimmedComment)\n\t\tif len(texts) > 1 {\n\t\t\treturn texts[1]\n\t\t}\n\t}\n\n\treturn \"\"\n}\n\nfunc commentWithoutNameOverride(comment string) string {\n\tif len(comment) == 0 {\n\t\treturn \"\"\n\t}\n\tcomment = strings.TrimPrefix(comment, \"//\")\n\tcomment = strings.TrimPrefix(comment, \"/*\")\n\tcomment = strings.TrimSuffix(comment, \"*/\")\n\tcomment = strings.TrimSpace(comment)\n\tcomment = overrideNameRegex.ReplaceAllString(comment, \"\")\n\tcomment = strings.TrimSpace(comment)\n\treturn comment\n}\n\n// IsComplexSchema whether a schema is complex and should be a ref schema\nfunc IsComplexSchema(schema *spec.Schema) bool {\n\t// a enum type should be complex\n\tif len(schema.Enum) > 0 {\n\t\treturn true\n\t}\n\n\t// a deep array type is complex, how to determine deep? here more than 2 ,for example: [][]object,[][][]int\n\tif len(schema.Type) > 2 {\n\t\treturn true\n\t}\n\n\t//Object included, such as Object or []Object\n\tfor _, st := range schema.Type {\n\t\tif st == OBJECT {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// IsRefSchema whether a schema is a reference schema.\nfunc IsRefSchema(schema *spec.Schema) bool {\n\treturn schema.Ref.Ref.GetURL() != nil\n}\n\n// RefSchema build a reference schema.\nfunc RefSchema(refType string) *spec.Schema {\n\treturn spec.RefSchema(\"#/definitions/\" + refType)\n}\n\n// PrimitiveSchema build a primitive schema.\nfunc PrimitiveSchema(refType string) *spec.Schema {\n\treturn &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{refType}}}\n}\n\n// BuildCustomSchema build custom schema specified by tag swaggertype.\nfunc BuildCustomSchema(types []string) (*spec.Schema, error) {\n\tif len(types) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tswitch types[0] {\n\tcase PRIMITIVE:\n\t\tif len(types) == 1 {\n\t\t\treturn nil, errors.New(\"need primitive type after primitive\")\n\t\t}\n\n\t\treturn BuildCustomSchema(types[1:])\n\tcase ARRAY:\n\t\tif len(types) == 1 {\n\t\t\treturn nil, errors.New(\"need array item type after array\")\n\t\t}\n\n\t\tschema, err := BuildCustomSchema(types[1:])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn spec.ArrayProperty(schema), nil\n\tcase OBJECT:\n\t\tif len(types) == 1 {\n\t\t\treturn PrimitiveSchema(types[0]), nil\n\t\t}\n\n\t\tschema, err := BuildCustomSchema(types[1:])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn spec.MapProperty(schema), nil\n\tdefault:\n\t\terr := CheckSchemaType(types[0])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn PrimitiveSchema(types[0]), nil\n\t}\n}\n\n// MergeSchema merge schemas\nfunc MergeSchema(dst *spec.Schema, src *spec.Schema) *spec.Schema {\n\tif len(src.Type) > 0 {\n\t\tdst.Type = src.Type\n\t}\n\tif len(src.Properties) > 0 {\n\t\tdst.Properties = src.Properties\n\t}\n\tif src.Items != nil {\n\t\tdst.Items = src.Items\n\t}\n\tif src.AdditionalProperties != nil {\n\t\tdst.AdditionalProperties = src.AdditionalProperties\n\t}\n\tif len(src.Description) > 0 {\n\t\tdst.Description = src.Description\n\t}\n\tif src.Nullable {\n\t\tdst.Nullable = src.Nullable\n\t}\n\tif len(src.Format) > 0 {\n\t\tdst.Format = src.Format\n\t}\n\tif src.Default != nil {\n\t\tdst.Default = src.Default\n\t}\n\tif src.Example != nil {\n\t\tdst.Example = src.Example\n\t}\n\tif len(src.Extensions) > 0 {\n\t\tdst.Extensions = src.Extensions\n\t}\n\tif src.Maximum != nil {\n\t\tdst.Maximum = src.Maximum\n\t}\n\tif src.Minimum != nil {\n\t\tdst.Minimum = src.Minimum\n\t}\n\tif src.ExclusiveMaximum {\n\t\tdst.ExclusiveMaximum = src.ExclusiveMaximum\n\t}\n\tif src.ExclusiveMinimum {\n\t\tdst.ExclusiveMinimum = src.ExclusiveMinimum\n\t}\n\tif src.MaxLength != nil {\n\t\tdst.MaxLength = src.MaxLength\n\t}\n\tif src.MinLength != nil {\n\t\tdst.MinLength = src.MinLength\n\t}\n\tif len(src.Pattern) > 0 {\n\t\tdst.Pattern = src.Pattern\n\t}\n\tif src.MaxItems != nil {\n\t\tdst.MaxItems = src.MaxItems\n\t}\n\tif src.MinItems != nil {\n\t\tdst.MinItems = src.MinItems\n\t}\n\tif src.UniqueItems {\n\t\tdst.UniqueItems = src.UniqueItems\n\t}\n\tif src.MultipleOf != nil {\n\t\tdst.MultipleOf = src.MultipleOf\n\t}\n\tif len(src.Enum) > 0 {\n\t\tdst.Enum = src.Enum\n\t}\n\tif len(src.Extensions) > 0 {\n\t\tdst.Extensions = src.Extensions\n\t}\n\tif len(src.ExtraProps) > 0 {\n\t\tdst.ExtraProps = src.ExtraProps\n\t}\n\treturn dst\n}\n"
  },
  {
    "path": "schema_test.go",
    "content": "package swag\n\nimport (\n\t\"testing\"\n\n\t\"github.com/go-openapi/spec\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestValidDataType(t *testing.T) {\n\tt.Parallel()\n\n\tassert.NoError(t, CheckSchemaType(STRING))\n\tassert.NoError(t, CheckSchemaType(NUMBER))\n\tassert.NoError(t, CheckSchemaType(INTEGER))\n\tassert.NoError(t, CheckSchemaType(BOOLEAN))\n\tassert.NoError(t, CheckSchemaType(ARRAY))\n\tassert.NoError(t, CheckSchemaType(OBJECT))\n\n\tassert.Error(t, CheckSchemaType(\"oops\"))\n}\n\nfunc TestTransToValidSchemeType(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Equal(t, TransToValidSchemeType(\"uint\"), INTEGER)\n\tassert.Equal(t, TransToValidSchemeType(\"uint32\"), INTEGER)\n\tassert.Equal(t, TransToValidSchemeType(\"uint64\"), INTEGER)\n\tassert.Equal(t, TransToValidSchemeType(\"float32\"), NUMBER)\n\tassert.Equal(t, TransToValidSchemeType(\"bool\"), BOOLEAN)\n\tassert.Equal(t, TransToValidSchemeType(\"string\"), STRING)\n\n\t// should accept any type, due to user defined types\n\tother := \"oops\"\n\tassert.Equal(t, TransToValidSchemeType(other), other)\n}\n\nfunc TestTransToValidCollectionFormat(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Equal(t, TransToValidCollectionFormat(\"csv\"), \"csv\")\n\tassert.Equal(t, TransToValidCollectionFormat(\"multi\"), \"multi\")\n\tassert.Equal(t, TransToValidCollectionFormat(\"pipes\"), \"pipes\")\n\tassert.Equal(t, TransToValidCollectionFormat(\"tsv\"), \"tsv\")\n\tassert.Equal(t, TransToValidSchemeType(\"string\"), STRING)\n\n\t// should accept any type, due to user defined types\n\tassert.Equal(t, TransToValidCollectionFormat(\"oops\"), \"\")\n}\n\nfunc TestIsGolangPrimitiveType(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Equal(t, IsGolangPrimitiveType(\"uint\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"int\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"uint8\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"uint16\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"int16\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"byte\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"uint32\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"int32\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"rune\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"uint64\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"int64\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"float32\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"float64\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"bool\"), true)\n\tassert.Equal(t, IsGolangPrimitiveType(\"string\"), true)\n\n\tassert.Equal(t, IsGolangPrimitiveType(\"oops\"), false)\n}\n\nfunc TestIsSimplePrimitiveType(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Equal(t, IsSimplePrimitiveType(\"string\"), true)\n\tassert.Equal(t, IsSimplePrimitiveType(\"number\"), true)\n\tassert.Equal(t, IsSimplePrimitiveType(\"integer\"), true)\n\tassert.Equal(t, IsSimplePrimitiveType(\"boolean\"), true)\n\n\tassert.Equal(t, IsSimplePrimitiveType(\"oops\"), false)\n}\n\nfunc TestBuildCustomSchema(t *testing.T) {\n\tt.Parallel()\n\n\tvar (\n\t\tschema *spec.Schema\n\t\terr    error\n\t)\n\n\tschema, err = BuildCustomSchema([]string{})\n\tassert.NoError(t, err)\n\tassert.Nil(t, schema)\n\n\tschema, err = BuildCustomSchema([]string{\"primitive\"})\n\tassert.Error(t, err)\n\tassert.Nil(t, schema)\n\n\tschema, err = BuildCustomSchema([]string{\"primitive\", \"oops\"})\n\tassert.Error(t, err)\n\tassert.Nil(t, schema)\n\n\tschema, err = BuildCustomSchema([]string{\"primitive\", \"string\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema.SchemaProps.Type, spec.StringOrArray{\"string\"})\n\n\tschema, err = BuildCustomSchema([]string{\"array\"})\n\tassert.Error(t, err)\n\tassert.Nil(t, schema)\n\n\tschema, err = BuildCustomSchema([]string{\"array\", \"oops\"})\n\tassert.Error(t, err)\n\tassert.Nil(t, schema)\n\n\tschema, err = BuildCustomSchema([]string{\"array\", \"string\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema.SchemaProps.Type, spec.StringOrArray{\"array\"})\n\tassert.Equal(t, schema.SchemaProps.Items.Schema.SchemaProps.Type, spec.StringOrArray{\"string\"})\n\n\tschema, err = BuildCustomSchema([]string{\"object\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema.SchemaProps.Type, spec.StringOrArray{\"object\"})\n\n\tschema, err = BuildCustomSchema([]string{\"object\", \"oops\"})\n\tassert.Error(t, err)\n\tassert.Nil(t, schema)\n\n\tschema, err = BuildCustomSchema([]string{\"object\", \"string\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, schema.SchemaProps.Type, spec.StringOrArray{\"object\"})\n\tassert.Equal(t, schema.SchemaProps.AdditionalProperties.Schema.Type, spec.StringOrArray{\"string\"})\n}\n\nfunc TestIsNumericType(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Equal(t, IsNumericType(INTEGER), true)\n\tassert.Equal(t, IsNumericType(NUMBER), true)\n\n\tassert.Equal(t, IsNumericType(STRING), false)\n}\n\nfunc TestIsInterfaceLike(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Equal(t, IsInterfaceLike(ERROR), true)\n\tassert.Equal(t, IsInterfaceLike(ANY), true)\n\n\tassert.Equal(t, IsInterfaceLike(STRING), false)\n}\n"
  },
  {
    "path": "spec.go",
    "content": "package swag\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"strings\"\n\t\"text/template\"\n)\n\n// Spec holds exported Swagger Info so clients can modify it.\ntype Spec struct {\n\tVersion          string\n\tHost             string\n\tBasePath         string\n\tSchemes          []string\n\tTitle            string\n\tDescription      string\n\tInfoInstanceName string\n\tSwaggerTemplate  string\n\tLeftDelim        string\n\tRightDelim       string\n}\n\n// ReadDoc parses SwaggerTemplate into swagger document.\nfunc (i *Spec) ReadDoc() string {\n\ti.Description = strings.ReplaceAll(i.Description, \"\\n\", \"\\\\n\")\n\n\ttpl := template.New(\"swagger_info\").Funcs(template.FuncMap{\n\t\t\"marshal\": func(v any) string {\n\t\t\ta, _ := json.Marshal(v)\n\n\t\t\treturn string(a)\n\t\t},\n\t\t\"escape\": func(v any) string {\n\t\t\t// escape tabs\n\t\t\tvar str = strings.ReplaceAll(v.(string), \"\\t\", \"\\\\t\")\n\t\t\t// replace \" with \\\", and if that results in \\\\\", replace that with \\\\\\\"\n\t\t\tstr = strings.ReplaceAll(str, \"\\\"\", \"\\\\\\\"\")\n\n\t\t\treturn strings.ReplaceAll(str, \"\\\\\\\\\\\"\", \"\\\\\\\\\\\\\\\"\")\n\t\t},\n\t})\n\n\tif i.LeftDelim != \"\" && i.RightDelim != \"\" {\n\t\ttpl = tpl.Delims(i.LeftDelim, i.RightDelim)\n\t}\n\n\tparsed, err := tpl.Parse(i.SwaggerTemplate)\n\tif err != nil {\n\t\treturn i.SwaggerTemplate\n\t}\n\n\tvar doc bytes.Buffer\n\tif err = parsed.Execute(&doc, i); err != nil {\n\t\treturn i.SwaggerTemplate\n\t}\n\n\treturn doc.String()\n}\n\n// InstanceName returns Spec instance name.\nfunc (i *Spec) InstanceName() string {\n\treturn i.InfoInstanceName\n}\n"
  },
  {
    "path": "spec_test.go",
    "content": "package swag\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSpec_InstanceName(t *testing.T) {\n\ttype fields struct {\n\t\tVersion          string\n\t\tHost             string\n\t\tBasePath         string\n\t\tSchemes          []string\n\t\tTitle            string\n\t\tDescription      string\n\t\tInfoInstanceName string\n\t\tSwaggerTemplate  string\n\t}\n\n\ttests := []struct {\n\t\tname   string\n\t\tfields fields\n\t\twant   string\n\t}{\n\t\t{\n\t\t\tname: \"TestInstanceNameCorrect\",\n\t\t\tfields: fields{\n\t\t\t\tVersion:          \"1.0\",\n\t\t\t\tHost:             \"localhost:8080\",\n\t\t\t\tBasePath:         \"/\",\n\t\t\t\tInfoInstanceName: \"TestInstanceName1\",\n\t\t\t},\n\t\t\twant: \"TestInstanceName1\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdoc := Spec{\n\t\t\t\tVersion:          tt.fields.Version,\n\t\t\t\tHost:             tt.fields.Host,\n\t\t\t\tBasePath:         tt.fields.BasePath,\n\t\t\t\tSchemes:          tt.fields.Schemes,\n\t\t\t\tTitle:            tt.fields.Title,\n\t\t\t\tDescription:      tt.fields.Description,\n\t\t\t\tInfoInstanceName: tt.fields.InfoInstanceName,\n\t\t\t\tSwaggerTemplate:  tt.fields.SwaggerTemplate,\n\t\t\t}\n\n\t\t\tassert.Equal(t, tt.want, doc.InstanceName())\n\t\t})\n\t}\n}\n\nfunc TestSpec_ReadDoc(t *testing.T) {\n\ttype fields struct {\n\t\tVersion          string\n\t\tHost             string\n\t\tBasePath         string\n\t\tSchemes          []string\n\t\tTitle            string\n\t\tDescription      string\n\t\tInfoInstanceName string\n\t\tSwaggerTemplate  string\n\t\tLeftDelim        string\n\t\tRightDelim       string\n\t}\n\n\ttests := []struct {\n\t\tname   string\n\t\tfields fields\n\t\twant   string\n\t}{\n\t\t{\n\t\t\tname: \"TestReadDocCorrect\",\n\t\t\tfields: fields{\n\t\t\t\tVersion:          \"1.0\",\n\t\t\t\tHost:             \"localhost:8080\",\n\t\t\t\tBasePath:         \"/\",\n\t\t\t\tInfoInstanceName: \"TestInstanceName\",\n\t\t\t\tSwaggerTemplate: `{\n\t\t\t\"swagger\": \"2.0\",\n\t\t\t\"info\": {\n\t\t\t\t\"description\": \"{{escape .Description}}\",\n\t\t\t\t\"title\": \"{{.Title}}\",\n\t\t\t\t\"version\": \"{{.Version}}\"\n\t\t\t},\n\t\t\t\"host\": \"{{.Host}}\",\n\t\t\t\"basePath\": \"{{.BasePath}}\",\n\t\t}`,\n\t\t\t},\n\t\t\twant: \"{\" +\n\t\t\t\t\"\\n\\t\\t\\t\\\"swagger\\\": \\\"2.0\\\",\" +\n\t\t\t\t\"\\n\\t\\t\\t\\\"info\\\": {\" +\n\t\t\t\t\"\\n\\t\\t\\t\\t\\\"description\\\": \\\"\\\",\\n\\t\\t\\t\\t\\\"\" +\n\t\t\t\t\"title\\\": \\\"\\\",\" +\n\t\t\t\t\"\\n\\t\\t\\t\\t\\\"version\\\": \\\"1.0\\\"\" +\n\t\t\t\t\"\\n\\t\\t\\t},\" +\n\t\t\t\t\"\\n\\t\\t\\t\\\"host\\\": \\\"localhost:8080\\\",\" +\n\t\t\t\t\"\\n\\t\\t\\t\\\"basePath\\\": \\\"/\\\",\" +\n\t\t\t\t\"\\n\\t\\t}\",\n\t\t},\n\t\t{\n\t\t\tname: \"TestReadDocMarshalTrigger\",\n\t\t\tfields: fields{\n\t\t\t\tVersion:          \"1.0\",\n\t\t\t\tHost:             \"localhost:8080\",\n\t\t\t\tBasePath:         \"/\",\n\t\t\t\tInfoInstanceName: \"TestInstanceName\",\n\t\t\t\tSwaggerTemplate:  \"{{ marshal .Version }}\",\n\t\t\t},\n\t\t\twant: \"\\\"1.0\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"TestReadDocParseError\",\n\t\t\tfields: fields{\n\t\t\t\tVersion:          \"1.0\",\n\t\t\t\tHost:             \"localhost:8080\",\n\t\t\t\tBasePath:         \"/\",\n\t\t\t\tInfoInstanceName: \"TestInstanceName\",\n\t\t\t\tSwaggerTemplate:  \"{{ ..Version }}\",\n\t\t\t},\n\t\t\twant: \"{{ ..Version }}\",\n\t\t},\n\t\t{\n\t\t\tname: \"TestReadDocExecuteError\",\n\t\t\tfields: fields{\n\t\t\t\tVersion:          \"1.0\",\n\t\t\t\tHost:             \"localhost:8080\",\n\t\t\t\tBasePath:         \"/\",\n\t\t\t\tInfoInstanceName: \"TestInstanceName\",\n\t\t\t\tSwaggerTemplate:  \"{{ .Schemesa }}\",\n\t\t\t},\n\t\t\twant: \"{{ .Schemesa }}\",\n\t\t},\n\t\t{\n\t\t\tname: \"TestReadDocCustomDelims\",\n\t\t\tfields: fields{\n\t\t\t\tVersion:          \"1.0\",\n\t\t\t\tHost:             \"localhost:8080\",\n\t\t\t\tBasePath:         \"/\",\n\t\t\t\tInfoInstanceName: \"TestInstanceName\",\n\t\t\t\tSwaggerTemplate: `{\n\t\t\t\"swagger\": \"2.0\",\n\t\t\t\"info\": {\n\t\t\t\t\"description\": \"{%escape .Description%}\",\n\t\t\t\t\"title\": \"{%.Title%}\",\n\t\t\t\t\"version\": \"{%.Version%}\"\n\t\t\t},\n\t\t\t\"host\": \"{%.Host%}\",\n\t\t\t\"basePath\": \"{%.BasePath%}\",\n\t\t}`,\n\t\t\t\tLeftDelim:  \"{%\",\n\t\t\t\tRightDelim: \"%}\",\n\t\t\t},\n\t\t\twant: \"{\" +\n\t\t\t\t\"\\n\\t\\t\\t\\\"swagger\\\": \\\"2.0\\\",\" +\n\t\t\t\t\"\\n\\t\\t\\t\\\"info\\\": {\" +\n\t\t\t\t\"\\n\\t\\t\\t\\t\\\"description\\\": \\\"\\\",\\n\\t\\t\\t\\t\\\"\" +\n\t\t\t\t\"title\\\": \\\"\\\",\" +\n\t\t\t\t\"\\n\\t\\t\\t\\t\\\"version\\\": \\\"1.0\\\"\" +\n\t\t\t\t\"\\n\\t\\t\\t},\" +\n\t\t\t\t\"\\n\\t\\t\\t\\\"host\\\": \\\"localhost:8080\\\",\" +\n\t\t\t\t\"\\n\\t\\t\\t\\\"basePath\\\": \\\"/\\\",\" +\n\t\t\t\t\"\\n\\t\\t}\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdoc := Spec{\n\t\t\t\tVersion:          tt.fields.Version,\n\t\t\t\tHost:             tt.fields.Host,\n\t\t\t\tBasePath:         tt.fields.BasePath,\n\t\t\t\tSchemes:          tt.fields.Schemes,\n\t\t\t\tTitle:            tt.fields.Title,\n\t\t\t\tDescription:      tt.fields.Description,\n\t\t\t\tInfoInstanceName: tt.fields.InfoInstanceName,\n\t\t\t\tSwaggerTemplate:  tt.fields.SwaggerTemplate,\n\t\t\t\tLeftDelim:        tt.fields.LeftDelim,\n\t\t\t\tRightDelim:       tt.fields.RightDelim,\n\t\t\t}\n\n\t\t\tassert.Equal(t, tt.want, doc.ReadDoc())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "swagger.go",
    "content": "package swag\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n)\n\n// Name is a unique name be used to register swag instance.\nconst Name = \"swagger\"\n\nvar (\n\tswaggerMu sync.RWMutex\n\tswags     map[string]Swagger\n)\n\n// Swagger is an interface to read swagger document.\ntype Swagger interface {\n\tReadDoc() string\n}\n\n// Register registers swagger for given name.\nfunc Register(name string, swagger Swagger) {\n\tswaggerMu.Lock()\n\tdefer swaggerMu.Unlock()\n\n\tif swagger == nil {\n\t\tpanic(\"swagger is nil\")\n\t}\n\n\tif swags == nil {\n\t\tswags = make(map[string]Swagger)\n\t}\n\n\tif _, ok := swags[name]; ok {\n\t\tpanic(\"Register called twice for swag: \" + name)\n\t}\n\n\tswags[name] = swagger\n}\n\n// GetSwagger returns the swagger instance for given name.\n// If not found, returns nil.\nfunc GetSwagger(name string) Swagger {\n\tswaggerMu.RLock()\n\tdefer swaggerMu.RUnlock()\n\n\treturn swags[name]\n}\n\n// ReadDoc reads swagger document. An optional name parameter can be passed to read a specific document.\n// The default name is \"swagger\".\nfunc ReadDoc(optionalName ...string) (string, error) {\n\tswaggerMu.RLock()\n\tdefer swaggerMu.RUnlock()\n\n\tif swags == nil {\n\t\treturn \"\", errors.New(\"no swag has yet been registered\")\n\t}\n\n\tname := Name\n\tif len(optionalName) != 0 && optionalName[0] != \"\" {\n\t\tname = optionalName[0]\n\t}\n\n\tswag, ok := swags[name]\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"no swag named \\\"%s\\\" was registered\", name)\n\t}\n\n\treturn swag.ReadDoc(), nil\n}\n"
  },
  {
    "path": "swagger_test.go",
    "content": "package swag\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar doc = `{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {\n        \"/testapi/get-string-by-int/{some_id}\": {\n            \"get\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add a new pet to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"path\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"type\": \"int\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"type\": \"object\",\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"type\": \"object\",\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-struct-array-by-string/{some_id}\": {\n            \"get\": {\n                \"description\": \"get struct array by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"path\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    {\n                        \"description\": \"Offset\",\n                        \"name\": \"offset\",\n                        \"in\": \"query\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"type\": \"int\"\n                        }\n                    },\n                    {\n                        \"description\": \"Offset\",\n                        \"name\": \"limit\",\n                        \"in\": \"query\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"type\": \"int\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"type\": \"object\",\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"type\": \"object\",\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"web.APIError\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"ErrorCode\": {\n                    \"type\": \"int\"\n                },\n                \"ErrorMessage\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    },\n    \"securityDefinitions\": {\n        \"ApiKey\": {\n            \"description: \"some\",\n            \"type\": \"apiKey\",\n            \"name\": \"X-API-KEY\",\n            \"in\": \"header\"\n        }\n    }\n}`\n\ntype s struct{}\n\nfunc (s *s) ReadDoc() string {\n\treturn doc\n}\n\nfunc TestRegister(t *testing.T) {\n\tsetup()\n\tRegister(Name, &s{})\n\td, _ := ReadDoc()\n\tassert.Equal(t, doc, d)\n}\n\nfunc TestRegisterByName(t *testing.T) {\n\tsetup()\n\tRegister(\"another_name\", &s{})\n\td, _ := ReadDoc(\"another_name\")\n\tassert.Equal(t, doc, d)\n}\n\nfunc TestRegisterMultiple(t *testing.T) {\n\tsetup()\n\tRegister(Name, &s{})\n\tRegister(\"another_name\", &s{})\n\td1, _ := ReadDoc(Name)\n\td2, _ := ReadDoc(\"another_name\")\n\tassert.Equal(t, doc, d1)\n\tassert.Equal(t, doc, d2)\n}\n\nfunc TestReadDocBeforeRegistered(t *testing.T) {\n\tsetup()\n\t_, err := ReadDoc()\n\tassert.Error(t, err)\n}\n\nfunc TestReadDocWithInvalidName(t *testing.T) {\n\tsetup()\n\tRegister(Name, &s{})\n\t_, err := ReadDoc(\"invalid\")\n\tassert.Error(t, err)\n}\n\nfunc TestNilRegister(t *testing.T) {\n\tsetup()\n\tvar swagger Swagger\n\tassert.Panics(t, func() {\n\t\tRegister(Name, swagger)\n\t})\n}\n\nfunc TestCalledTwicelRegister(t *testing.T) {\n\tsetup()\n\tassert.Panics(t, func() {\n\t\tRegister(Name, &s{})\n\t\tRegister(Name, &s{})\n\t})\n}\n\nfunc setup() {\n\tswags = nil\n}\n\nfunc TestGetSwagger(t *testing.T) {\n\tsetup()\n\tinstance := &s{}\n\tRegister(Name, instance)\n\tswagger := GetSwagger(Name)\n\tassert.Equal(t, instance, swagger)\n\n\tswagger = GetSwagger(\"invalid\")\n\tassert.Nil(t, swagger)\n}\n"
  },
  {
    "path": "testdata/alias_import/api/api.go",
    "content": "package api\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/alias_import/data\"\n\t\"github.com/swaggo/swag/testdata/alias_type/types\"\n)\n\n// @Summary Get application\n// @Description test get application\n// @ID get-application\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} data.ApplicationResponse\t\"ok\"\n// @Router /testapi/application [get]\nfunc GetApplication(w http.ResponseWriter, r *http.Request) {\n\tvar foo = data.ApplicationResponse{\n\t\tApplication: types.Application{\n\t\t\tName: \"name\",\n\t\t},\n\t\tApplicationArray: []types.Application{\n\t\t\t{Name: \"name\"},\n\t\t},\n\t}\n\tlog.Println(foo)\n\t//write your code\n}\n"
  },
  {
    "path": "testdata/alias_import/data/applicationresponse.go",
    "content": "package data\n\nimport (\n\ttypesapplication \"github.com/swaggo/swag/testdata/alias_import/types\"\n)\n\ntype ApplicationResponse struct {\n\ttypesapplication.TypeToEmbed\n\n\tApplication      typesapplication.Application   `json:\"application\"`\n\tApplicationArray []typesapplication.Application `json:\"application_array\"`\n\tApplicationTime  typesapplication.DateOnly      `json:\"application_time\"`\n}\n"
  },
  {
    "path": "testdata/alias_import/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {\n        \"/testapi/application\": {\n            \"get\": {\n                \"description\": \"test get application\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Get application\",\n                \"operationId\": \"get-application\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/data.ApplicationResponse\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"data.ApplicationResponse\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"application\": {\n                    \"$ref\": \"#/definitions/types.Application\"\n                },\n                \"application_array\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Application\"\n                    }\n                },\n                \"application_time\": {\n                    \"type\": \"string\"\n                },\n                \"embedded\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.Application\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/alias_import/main.go",
    "content": "package alias_import\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/alias_import/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\nfunc main() {\n\thttp.HandleFunc(\"/testapi/application\", api.GetApplication)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/alias_import/types/application.go",
    "content": "package types\n\nimport \"time\"\n\ntype Application struct {\n\tName string\n}\n\ntype DateOnly time.Time\n\ntype TypeToEmbed struct {\n\tEmbedded string\n}\n"
  },
  {
    "path": "testdata/alias_nested/cmd/main/main.go",
    "content": "package main\n\nimport \"github.com/swaggo/swag/testdata/alias_nested/pkg/good\"\n\n// @Success 200 {object} good.Gen\n// @Router /api [get].\nfunc main() {\n\tvar _ good.Gen\n}\n"
  },
  {
    "path": "testdata/alias_nested/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"contact\": {}\n    },\n    \"paths\": {\n        \"/api\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/Gen\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"Gen\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"emb\": {\n                    \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_alias_nested_pkg_good.Emb\"\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_alias_nested_pkg_good.Emb\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"good\": {\n                    \"type\": \"boolean\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/alias_nested/pkg/bad/data.go",
    "content": "package bad\n\ntype Emb struct {\n\tBad bool `json:\"bad\"`\n} // @name Emb\n"
  },
  {
    "path": "testdata/alias_nested/pkg/good/data.go",
    "content": "package good\n\ntype Gen struct {\n\tEmb Emb `json:\"emb\"`\n} // @name Gen\n\ntype Emb struct {\n\tGood bool `json:\"good\"`\n}\n"
  },
  {
    "path": "testdata/alias_type/api/api.go",
    "content": "package api\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/swaggo/swag/testdata/alias_type/data\"\n)\n\n/*// @Summary Get time as string\n// @Description get time as string\n// @ID time-as-string\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} data.StringAlias\t\"ok\"\n// @Router /testapi/time-as-string [get]\nfunc GetTimeAsStringAlias(w http.ResponseWriter, r *http.Request) {\n\tvar foo data.StringAlias = \"test\"\n\tlog.Println(foo)\n\t//write your code\n}*/\n\n/*// @Summary Get time as time\n// @Description get time as time\n// @ID time-as-time\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} data.DateOnly\t\"ok\"\n// @Router /testapi/time-as-time [get]\nfunc GetTimeAsTimeAlias(w http.ResponseWriter, r *http.Request) {\n\tvar foo = data.DateOnly(time.Now())\n\tlog.Println(foo)\n\t//write your code\n}*/\n\n// @Summary Get container with time and time alias\n// @Description test container with time and time alias\n// @ID time-as-time-container\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} data.TimeContainer\t\"ok\"\n// @Router /testapi/time-as-time-container [get]\nfunc GetTimeAsTimeContainer(w http.ResponseWriter, r *http.Request) {\n\tnow := time.Now()\n\tvar foo = data.TimeContainer{\n\t\tName:      \"test\",\n\t\tTimestamp: now,\n\t\t//CreatedAt: &now,\n\t}\n\tlog.Println(foo)\n\t//write your code\n}\n"
  },
  {
    "path": "testdata/alias_type/data/alias.go",
    "content": "package data\n\nimport (\n\t\"github.com/swaggo/swag/testdata/alias_type/types\"\n\t\"time\"\n)\n\ntype TimeContainer struct {\n\tName      types.StringAlias `json:\"name\"`\n\tTimestamp time.Time         `json:\"timestamp\"`\n\tCreatedAt types.DateOnly    `json:\"created_at\"`\n}\n"
  },
  {
    "path": "testdata/alias_type/main.go",
    "content": "package alias_type\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/alias_type/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\nfunc main() {\n\thttp.HandleFunc(\"/testapi/time-as-time-container\", api.GetTimeAsTimeContainer)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/alias_type/types/alias.go",
    "content": "package types\n\nimport \"time\"\n\ntype StringAlias string\n\ntype DateOnly time.Time\n"
  },
  {
    "path": "testdata/api.md",
    "content": "Swagger Example API Markdown Description"
  },
  {
    "path": "testdata/code_examples/api/api1.go",
    "content": "package api\n\nimport (\n\t_ \"github.com/swaggo/swag/testdata/conflict_name/model\"\n\t\"net/http\"\n)\n\n// @Description  Check if Health  of service it's OK!\n// @Router /health [get]\n// @x-codeSamples file\nfunc Get1(w http.ResponseWriter, r *http.Request) {\n\n}\n"
  },
  {
    "path": "testdata/code_examples/broken.json",
    "content": "{\n  \"key\": value\n}"
  },
  {
    "path": "testdata/code_examples/example.json",
    "content": "{\n    \"lang\": \"JavaScript\",\n    \"source\": \"console.log('Hello World');\"\n}"
  },
  {
    "path": "testdata/code_examples/main.go",
    "content": "package main\n\n// @title Swag test\n// @version 1.0\n// @description test for conflict name\nfunc main() {\n\n}\n"
  },
  {
    "path": "testdata/composition/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/composition/common\"\n)\n\ntype Foo struct {\n\tField1 string\n}\ntype Bar struct {\n\tField2 string\n}\ntype EmptyStruct struct {\n}\ntype unexported struct {\n}\ntype Ignored struct {\n\tField5 string `swaggerignore:\"true\"`\n}\n\ntype FooBar struct {\n\tFoo\n\tBar\n\tEmptyStruct\n\tunexported\n\tIgnored\n}\n\ntype FooBarPointer struct {\n\t*common.ResponseFormat\n\t*Foo\n\t*Bar\n\t*EmptyStruct\n\t*unexported\n\t*Ignored\n}\n\ntype BarMap map[string]Bar\n\ntype FooBarMap struct {\n\tField3 map[string]MapValue\n}\n\ntype MapValue struct {\n\tField4 string\n}\n\n// @Description get Foo\n// @ID get-foo\n// @Accept json\n// @Produce json\n// @Success 200 {object} api.Foo\n// @Router /testapi/get-foo [get]\nfunc GetFoo(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\tvar _ = Foo{}\n}\n\n// @Description get Bar\n// @ID get-bar\n// @Accept json\n// @Produce json\n// @Success 200 {object} api.Bar\n// @Router /testapi/get-bar [get]\nfunc GetBar(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\tvar _ = Bar{}\n}\n\n// @Description get FooBar\n// @ID get-foobar\n// @Accept json\n// @Produce json\n// @Success 200 {object} api.FooBar\n// @Router /testapi/get-foobar [get]\nfunc GetFooBar(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\tvar _ = FooBar{}\n}\n\n// @Description get FooBarPointer\n// @ID get-foobar-pointer\n// @Accept json\n// @Produce json\n// @Success 200 {object} api.FooBarPointer\n// @Router /testapi/get-foobar-pointer [get]\nfunc GetFooBarPointer(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\tvar _ = FooBarPointer{}\n}\n\n// @Description get BarMap\n// @ID get-bar-map\n// @Accept json\n// @Produce json\n// @Success 200 {object} api.BarMap\n// @Router /testapi/get-barmap [get]\nfunc GetBarMap(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\tvar _ = BarMap{}\n}\n\n// @Description get FoorBarMap\n// @ID get-foo-bar-map\n// @Accept json\n// @Produce json\n// @Success 200 {object} api.FooBarMap\n// @Router /testapi/get-foobarmap [get]\nfunc GetFooBarMap(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\tvar _ = FooBarMap{}\n}\n"
  },
  {
    "path": "testdata/composition/common/response.go",
    "content": "package common\n\ntype ResponseFormat struct {\n\tMessage string `json:\"message\"`\n}\n"
  },
  {
    "path": "testdata/composition/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {\n        \"/testapi/get-bar\": {\n            \"get\": {\n                \"description\": \"get Bar\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"operationId\": \"get-bar\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.Bar\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-barmap\": {\n            \"get\": {\n                \"description\": \"get BarMap\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"operationId\": \"get-bar-map\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.BarMap\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-foo\": {\n            \"get\": {\n                \"description\": \"get Foo\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"operationId\": \"get-foo\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.Foo\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-foobar\": {\n            \"get\": {\n                \"description\": \"get FooBar\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"operationId\": \"get-foobar\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.FooBar\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-foobar-pointer\": {\n            \"get\": {\n                \"description\": \"get FooBarPointer\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"operationId\": \"get-foobar-pointer\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.FooBarPointer\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-foobarmap\": {\n            \"get\": {\n                \"description\": \"get FoorBarMap\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"operationId\": \"get-foo-bar-map\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.FooBarMap\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"api.Bar\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"field2\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.BarMap\": {\n            \"type\": \"object\",\n            \"additionalProperties\": {\n                \"$ref\": \"#/definitions/api.Bar\"\n            }\n        },\n        \"api.Foo\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"field1\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.FooBar\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"field1\": {\n                    \"type\": \"string\"\n                },\n                \"field2\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.FooBarMap\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"field3\": {\n                    \"type\": \"object\",\n                    \"additionalProperties\": {\n                        \"$ref\": \"#/definitions/api.MapValue\"\n                    }\n                }\n            }\n        },\n        \"api.FooBarPointer\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"field1\": {\n                    \"type\": \"string\"\n                },\n                \"field2\": {\n                    \"type\": \"string\"\n                },\n                \"message\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.MapValue\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"field4\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/composition/main.go",
    "content": "package composition\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/composition/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server\n// @termsOfService http://swagger.io/terms/\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\nfunc main() {\n\thttp.handleFunc(\"/testapi/get-foo\", api.GetFoo)\n\thttp.handleFunc(\"/testapi/get-bar\", api.GetBar)\n\thttp.handleFunc(\"/testapi/get-foobar\", api.GetFooBar)\n\thttp.handleFunc(\"/testapi/get-foobar-pointer\", api.GetFooBarPointer)\n\thttp.handleFunc(\"/testapi/get-barmap\", api.GetBarMap)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/conflict_name/api/api1.go",
    "content": "package api\n\nimport (\n\t_ \"github.com/swaggo/swag/testdata/conflict_name/model\"\n\t\"net/http\"\n)\n\n// @Tags Health\n// @Description  Check if Health  of service it's OK!\n// @ID health\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} model.ErrorsResponse\n// @Router /health [get]\nfunc Get1(w http.ResponseWriter, r *http.Request) {\n\n}\n"
  },
  {
    "path": "testdata/conflict_name/api/api2.go",
    "content": "package api\n\nimport (\n\t_ \"github.com/swaggo/swag/testdata/conflict_name/model2\"\n\t\"net/http\"\n)\n\n// @Tags Health\n// @Description Check if Health  of service it's OK!\n// @ID health2\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} model.ErrorsResponse\n// @Router /health2 [get]\nfunc Get2(w http.ResponseWriter, r *http.Request) {\n\n}\n"
  },
  {
    "path": "testdata/conflict_name/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"test for conflict name\",\n        \"title\": \"Swag test\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"paths\": {\n        \"/health\": {\n            \"get\": {\n                \"description\": \"Check if Health  of service it's OK!\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"tags\": [\n                    \"Health\"\n                ],\n                \"operationId\": \"health\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_conflict_name_model.ErrorsResponse\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/health2\": {\n            \"get\": {\n                \"description\": \"Check if Health  of service it's OK!\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"tags\": [\n                    \"Health\"\n                ],\n                \"operationId\": \"health2\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_conflict_name_model2.ErrorsResponse\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"github_com_swaggo_swag_testdata_conflict_name_model.ErrorsResponse\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"newTime\": {\n                    \"$ref\": \"#/definitions/model.MyPayload\"\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_conflict_name_model.MyStruct\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_conflict_name_model2.ErrorsResponse\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"newTime\": {\n                    \"$ref\": \"#/definitions/model.MyPayload2\"\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_conflict_name_model2.MyStruct\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"model.MyPayload\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"my\": {\n                    \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_conflict_name_model.MyStruct\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"model.MyPayload2\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"my\": {\n                    \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_conflict_name_model2.MyStruct\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/conflict_name/main.go",
    "content": "package main\n\n// @title Swag test\n// @version 1.0\n// @description test for conflict name\nfunc main() {\n\n}\n"
  },
  {
    "path": "testdata/conflict_name/model/model.go",
    "content": "package model\n\ntype MyStruct struct {\n\tName string `json:\"name\"`\n}\n\ntype MyPayload struct {\n\tMy   MyStruct\n\tName string `json:\"name\"`\n}\n\ntype ErrorsResponse struct {\n\tNewTime MyPayload\n}\n"
  },
  {
    "path": "testdata/conflict_name/model2/model.go",
    "content": "package model\n\ntype MyStruct struct {\n\tName string `json:\"name\"`\n}\n\ntype MyPayload2 struct {\n\tMy   MyStruct\n\tName string `json:\"name\"`\n}\n\ntype ErrorsResponse struct {\n\tNewTime MyPayload2\n}\n"
  },
  {
    "path": "testdata/delims/api/api.go",
    "content": "package api\n\n// MyFunc godoc\n// @Description My Function\n// @Success 200 {object} MyStruct\n// @Router /myfunc [get]\nfunc MyFunc() {}\n\ntype MyStruct struct {\n\tURLTemplate string `json:\"urltemplate\" example:\"http://example.org/{{ path }}\" swaggertype:\"string\"`\n}\n"
  },
  {
    "path": "testdata/delims/expected.json",
    "content": "{\n    \"schemes\": [],\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"Testing custom template delimeters\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"\",\n    \"basePath\": \"\",\n    \"paths\": {\n        \"/myfunc\": {\n            \"get\": {\n                \"description\": \"My Function\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.MyStruct\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"api.MyStruct\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"urltemplate\": {\n                    \"type\": \"string\",\n                    \"example\": \"http://example.org/{{ path }}\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/delims/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/swaggo/swag\"\n\t\"github.com/swaggo/swag/testdata/delims/api\"\n\t_ \"github.com/swaggo/swag/testdata/delims/docs\"\n)\n\nfunc ReadDoc() string {\n\tdoc, _ := swag.ReadDoc(\"CustomDelims\")\n\treturn doc\n}\n\n// @title Swagger Example API\n// @version 1.0\n// @description Testing custom template delimeters\n// @termsOfService http://swagger.io/terms/\n\nfunc main() {\n\tapi.MyFunc()\n}\n"
  },
  {
    "path": "testdata/deprecated_router/api/api.go",
    "content": "package api\n\nimport \"net/http\"\n\n// @Description add Foo\n// @Deprecated\n// @Success 200 {string} string\n// @Router /testapi/foo1 [put]\n// @Router /testapi/foo1 [post]\n// @Router /test/api/foo1 [post]\nfunc AddFoo(w http.ResponseWriter, r *http.Request) {}\n\n// @Description get Foo\n// @Success 200 {string} string\n// @Router /testapi/foo1 [get]\n// @DeprecatedRouter /test/api/foo1 [get]\nfunc GetFoo(w http.ResponseWriter, r *http.Request) {}\n"
  },
  {
    "path": "testdata/deprecated_router/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"test data for deprecated router\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"paths\": {\n        \"/test/api/foo1\": {\n            \"get\": {\n                \"description\": \"get Foo\",\n                \"deprecated\": true,\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    }\n                }\n            },\n            \"post\": {\n                \"description\": \"add Foo\",\n                \"deprecated\": true,\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/foo1\": {\n            \"get\": {\n                \"description\": \"get Foo\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    }\n                }\n            },\n            \"put\": {\n                \"description\": \"add Foo\",\n                \"deprecated\": true,\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    }\n                }\n            },\n            \"post\": {\n                \"description\": \"add Foo\",\n                \"deprecated\": true,\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/deprecated_router/main.go",
    "content": "package main\n\n// @title Swagger Example API\n// @version 1.0\n// @description test data for deprecated router\n// @termsOfService http://swagger.io/terms/\n\nfunc main() {\n}\n"
  },
  {
    "path": "testdata/deps_having_invalid_pkg/main.go",
    "content": "package main\n\nimport _ \"golang.org/x/tools/go/loader\" // it inside contains invalid package files\nfunc main()                             {}\n"
  },
  {
    "path": "testdata/description_line_continuation/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n)\n\n// @Summary Endpoint A\n// @Description This is a mock endpoint description \\\n// @Description which is long and descriptions that \\\n// @Description end with backslash do not add a new line.\n// @Description This sentence is in a new line.\n// @Description\n// @Description And this have an empty line above it.\n// @Description Lorem ipsum dolor sit amet \\\n// @Description consectetur adipiscing elit, \\\n// @Description sed do eiusmod tempor incididunt \\\n// @Description ut labore et dolore magna aliqua.\n// @Success 200\n// @Router /a [get]\nfunc EndpointA(w http.ResponseWriter, r *http.Request) {\n\tw.WriteHeader(http.StatusOK)\n}\n\n// @Summary Endpoint B\n// @Description Something something.\n// @Description\n// @Description A new line, \\\n// @Description continue to the line.\n// @Success 200\n// @Router /b [get]\nfunc EndpointB(w http.ResponseWriter, r *http.Request) {\n\tw.WriteHeader(http.StatusOK)\n}\n"
  },
  {
    "path": "testdata/description_line_continuation/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"Example long description that should not be split into multiple lines.\\nThis is a new line thatescapes new line withoutadding a whitespace.\\n\\nAnother line that has an empty line above it.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:8080\",\n    \"paths\": {\n        \"/a\": {\n            \"get\": {\n                \"description\": \"This is a mock endpoint description which is long and descriptions that end with backslash do not add a new line.\\nThis sentence is in a new line.\\n\\nAnd this have an empty line above it.\\nLorem ipsum dolor sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\",\n                \"summary\": \"Endpoint A\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\"\n                    }\n                }\n            }\n        },\n        \"/b\": {\n            \"get\": {\n                \"description\": \"Something something.\\n\\nA new line, continue to the line.\",\n                \"summary\": \"Endpoint B\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\"\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/description_line_continuation/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/description_escape_new_line/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description Example long description \\\n// @description that should not be split \\\n// @description into multiple lines.\n// @description This is a new line that\\\n// @description escapes new line without\\\n// @description adding a whitespace.\n// @description\n// @description Another line that has an \\\n// @description empty line above it.\n// @host localhost:8080\nfunc main() {\n\thttp.HandleFunc(\"/a\", api.EndpointA)\n\thttp.HandleFunc(\"/b\", api.EndpointB)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/duplicated/api/api.go",
    "content": "package api\n\nimport \"net/http\"\n\n// @Description get Foo\n// @ID get-foo\n// @Success 200 {string} string\n// @Router /testapi/get-foo [get]\nfunc GetFoo(w http.ResponseWriter, r *http.Request) {}\n\n// @Description post Bar\n// @ID get-foo\n// @Success 200 {string} string\n// @Router /testapi/post-bar [post]\nfunc PostBar(w http.ResponseWriter, r *http.Request) {}\n"
  },
  {
    "path": "testdata/duplicated/main.go",
    "content": "package composition\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/duplicated/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server\n// @termsOfService http://swagger.io/terms/\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\nfunc main() {\n\thttp.HandleFunc(\"/testapi/get-foo\", api.GetFoo)\n\thttp.HandleFunc(\"/testapi/post-bar\", api.PostBar)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/duplicated2/api/api.go",
    "content": "package api\n\nimport \"net/http\"\n\n// @Description put Foo\n// @ID put-foo\n// @Success 200 {string} string\n// @Router /testapi/put-foo [put]\nfunc PutFoo(w http.ResponseWriter, r *http.Request) {}\n\n// @Description head Foo\n// @ID head-foo\n// @Success 200 {string} string\n// @Router /testapi/head-foo [head]\nfunc HeadFoo(w http.ResponseWriter, r *http.Request) {}\n\n// @Description options Foo\n// @ID options-foo\n// @Success 200 {string} string\n// @Router /testapi/options-foo [options]\nfunc OptionsFoo(w http.ResponseWriter, r *http.Request) {}\n\n// @Description patch Foo\n// @ID patch-foo\n// @Success 200 {string} string\n// @Router /testapi/patch-foo [patch]\nfunc PatchFoo(w http.ResponseWriter, r *http.Request) {}\n\n// @Description delete Foo\n// @ID put-foo\n// @Success 200 {string} string\n// @Router /testapi/delete-foo [delete]\nfunc DeleteFoo(w http.ResponseWriter, r *http.Request) {}\n"
  },
  {
    "path": "testdata/duplicated2/main.go",
    "content": "package composition\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/duplicated2/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server\n// @termsOfService http://swagger.io/terms/\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\nfunc main() {\n\thttp.HandleFunc(\"/testapi/put-foo\", api.PutFoo)\n\thttp.HandleFunc(\"/testapi/head-foo\", api.HeadFoo)\n\thttp.HandleFunc(\"/testapi/options-foo\", api.OptionsFoo)\n\thttp.HandleFunc(\"/testapi/patch-foo\", api.PatchFoo)\n\thttp.HandleFunc(\"/testapi/delete-foo\", api.DeleteFoo)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/duplicated_function_scoped/api/api.go",
    "content": "package api\n\nimport \"net/http\"\n\n// @Description get Foo\n// @ID get-foo\n// @Success 200 {object} api.GetFoo.response\n// @Router /testapi/get-foo [get]\nfunc GetFoo(w http.ResponseWriter, r *http.Request) {\n\ttype response struct {\n\t}\n}\n"
  },
  {
    "path": "testdata/duplicated_function_scoped/main.go",
    "content": "package composition\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/duplicated_function_scoped/api\"\n\totherapi \"github.com/swaggo/swag/testdata/duplicated_function_scoped/other_api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server\n// @termsOfService http://swagger.io/terms/\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\nfunc main() {\n\thttp.HandleFunc(\"/testapi/get-foo\", api.GetFoo)\n\thttp.HandleFunc(\"/testapi/post-bar\", otherapi.GetFoo)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/duplicated_function_scoped/other_api/api.go",
    "content": "package api\n\nimport \"net/http\"\n\n// @Description get Foo\n// @ID get-foo\n// @Success 200 {object} api.GetFoo.response\n// @Router /testapi/get-foo [get]\nfunc GetFoo(w http.ResponseWriter, r *http.Request) {\n\ttype response struct {\n\t}\n}\n"
  },
  {
    "path": "testdata/enums/api/api.go",
    "content": "package api\n\nimport \"github.com/swaggo/swag/testdata/enums/types\"\n\n//\t post students\n//\n//\t\t@Summary      test enums in response models\n//\t\t@Description  test enums in response models\n//\t\t@Failure      400   {object}  types.Person  \"ok\"\n//\t\t@Router       /students [post]\nfunc API() {\n\t_ = types.Person{}\n}\n\n//\t get students\n//\n//\t\t@Summary      test enums in response request\n//\t\t@Description  test enums in response request\n//\t\t@Param \t\t  typeinquery query []types.Type true \"type\"\n//\t\t@Param \t\t  typeinheader header types.Type true \"type\"\n//\t\t@Param \t\t  typeinpath path types.Type true \"type\"\n//\t\t@Success      200   \"ok\"\n//\t\t@Router       /students/{typeinpath}/ [get]\nfunc API2() {\n\t_ = types.Person{}\n}\n\n//\t post students\n//\n//\t\t@Summary      test enums fields in formdata request\n//\t\t@Description  test enums fields in formdata request\n//\t\t@Param \t\t  student formData types.Person true \"type\"\n//\t\t@Success      200   \"ok\"\n//\t\t@Router       /students2 [get]\nfunc API3() {\n\t_ = types.Person{}\n}\n\n//\t post students\n//\n//\t\t@Summary      test array enums fields in formdata request\n//\t\t@Description  test array enums fields in formdata request\n//\t\t@Param \t\t  student formData types.PersonWithArrayEnum true \"type\"\n//\t\t@Success      200   \"ok\"\n//\t\t@Router       /students4 [get]\nfunc API4() {\n\t_ = types.Person{}\n}\n"
  },
  {
    "path": "testdata/enums/consts/const.go",
    "content": "package consts\n\nconst Base = 1\n\nconst uintSize = 32 << (^uint(uintptr(0)) >> 63)\nconst maxBase = 10 + ('z' - 'a' + 1) + ('Z' - 'A' + 1)\nconst shlByLen = 1 << len(\"aaa\")\nconst hexnum = 0xFF\nconst octnum = 017\nconst nonescapestr = `aa\\nbb\\u8888cc`\nconst escapestr = \"aa\\nbb\\u8888cc\"\nconst escapechar = '\\u8888'\nconst underscored = 1_000_000\nconst binaryInteger = 0b10001000\nconst octInteger = 0o755\n"
  },
  {
    "path": "testdata/enums/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"basePath\": \"/v2\",\n    \"paths\": {\n        \"/students\": {\n            \"post\": {\n                \"description\": \"test enums in response models\",\n                \"summary\": \"test enums in response models\",\n                \"responses\": {\n                    \"400\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/types.Person\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/students/{typeinpath}/\": {\n            \"get\": {\n                \"description\": \"test enums in response request\",\n                \"summary\": \"test enums in response request\",\n                \"parameters\": [\n                    {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"enum\": [\n                                \"teacher\",\n                                \"student\",\n                                \"Other\"\n                            ],\n                            \"type\": \"string\"\n                        },\n                        \"description\": \"type\",\n                        \"name\": \"typeinquery\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"enum\": [\n                            \"teacher\",\n                            \"student\",\n                            \"Other\"\n                        ],\n                        \"type\": \"string\",\n                        \"description\": \"type\",\n                        \"name\": \"typeinheader\",\n                        \"in\": \"header\",\n                        \"required\": true\n                    },\n                    {\n                        \"enum\": [\n                            \"teacher\",\n                            \"student\",\n                            \"Other\"\n                        ],\n                        \"type\": \"string\",\n                        \"description\": \"type\",\n                        \"name\": \"typeinpath\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\"\n                    }\n                }\n            }\n        },\n        \"/students2\": {\n            \"get\": {\n                \"description\": \"test enums fields in formdata request\",\n                \"summary\": \"test enums fields in formdata request\",\n                \"parameters\": [\n                    {\n                        \"enum\": [\n                            -1,\n                            1,\n                            2,\n                            3,\n                            4,\n                            5\n                        ],\n                        \"type\": \"integer\",\n                        \"x-enum-comments\": {\n                            \"A\": \"AAA\",\n                            \"B\": \"BBB\"\n                        },\n                        \"x-enum-descriptions\": [\n                            \"\",\n                            \"AAA\",\n                            \"BBB\",\n                            \"\",\n                            \"\",\n                            \"\"\n                        ],\n                        \"x-enum-varnames\": [\n                            \"None\",\n                            \"A\",\n                            \"B\",\n                            \"C\",\n                            \"D\",\n                            \"F\"\n                        ],\n                        \"name\": \"class\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"enum\": [\n                            \"easy\",\n                            \"medium\",\n                            \"hard\"\n                        ],\n                        \"type\": \"string\",\n                        \"x-enum-comments\": {\n                            \"DifficultyHard\": \"This means really hard\",\n                            \"Medium\": \"This one also has a comment\"\n                        },\n                        \"x-enum-descriptions\": [\n                            \"\",\n                            \"This one also has a comment\",\n                            \"This means really hard\"\n                        ],\n                        \"x-enum-varnames\": [\n                            \"Easy\",\n                            \"Medium\",\n                            \"DifficultyHard\"\n                        ],\n                        \"name\": \"difficulty\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"enum\": [\n                            \"g_easy\",\n                            \"g_medium\",\n                            \"g_hard\"\n                        ],\n                        \"type\": \"string\",\n                        \"x-enum-comments\": {\n                            \"GenericDifficultyHard\": \"This means really hard\",\n                            \"GenericMedium\": \"This one also has a comment\"\n                        },\n                        \"x-enum-descriptions\": [\n                            \"\",\n                            \"This one also has a comment\",\n                            \"This means really hard\"\n                        ],\n                        \"x-enum-varnames\": [\n                            \"GenericEasy\",\n                            \"GenericMedium\",\n                            \"GenericDifficultyHard\"\n                        ],\n                        \"name\": \"genericDifficulty\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"enum\": [\n                            1,\n                            2,\n                            4,\n                            8,\n                            3\n                        ],\n                        \"type\": \"integer\",\n                        \"x-enum-comments\": {\n                            \"Mask1\": \"Mask1\",\n                            \"Mask2\": \"Mask2\",\n                            \"Mask3\": \"Mask3\",\n                            \"Mask4\": \"Mask4\"\n                        },\n                        \"x-enum-descriptions\": [\n                            \"Mask1\",\n                            \"Mask2\",\n                            \"Mask3\",\n                            \"Mask4\",\n                            \"\"\n                        ],\n                        \"x-enum-varnames\": [\n                            \"Mask1\",\n                            \"Mask2\",\n                            \"Mask3\",\n                            \"Mask4\",\n                            \"Mask5\"\n                        ],\n                        \"name\": \"mask\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"type\": \"string\",\n                        \"name\": \"name\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"enum\": [\n                            0,\n                            1,\n                            2\n                        ],\n                        \"type\": \"integer\",\n                        \"x-enum-comments\": {\n                            \"SecurityClearanceSensitive\": \"Name override and comment rules apply here just as above\",\n                            \"SuperSecret\": \"This one has a name override and a comment\"\n                        },\n                        \"x-enum-descriptions\": [\n                            \"\",\n                            \"Name override and comment rules apply here just as above\",\n                            \"This one has a name override and a comment\"\n                        ],\n                        \"x-enum-varnames\": [\n                            \"Public\",\n                            \"SecurityClearanceSensitive\",\n                            \"SuperSecret\"\n                        ],\n                        \"name\": \"securityClearance\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"enum\": [\n                            77,\n                            70\n                        ],\n                        \"type\": \"integer\",\n                        \"format\": \"int32\",\n                        \"x-enum-varnames\": [\n                            \"Male\",\n                            \"Female\"\n                        ],\n                        \"name\": \"sex\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"enum\": [\n                            \"teacher\",\n                            \"student\",\n                            \"Other\"\n                        ],\n                        \"type\": \"string\",\n                        \"x-enum-comments\": {\n                            \"Other\": \"Other\",\n                            \"Student\": \"student\",\n                            \"Teacher\": \"teacher\"\n                        },\n                        \"x-enum-descriptions\": [\n                            \"teacher\",\n                            \"student\",\n                            \"Other\"\n                        ],\n                        \"x-enum-varnames\": [\n                            \"Teacher\",\n                            \"Student\",\n                            \"Other\"\n                        ],\n                        \"name\": \"type\",\n                        \"in\": \"formData\"\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\"\n                    }\n                }\n            }\n        },\n        \"/students4\": {\n            \"get\": {\n                \"description\": \"test array enums fields in formdata request\",\n                \"summary\": \"test array enums fields in formdata request\",\n                \"parameters\": [\n                    {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"enum\": [\n                                -1,\n                                1,\n                                2,\n                                3,\n                                4,\n                                5\n                            ],\n                            \"type\": \"integer\"\n                        },\n                        \"name\": \"class\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"enum\": [\n                                \"easy\",\n                                \"medium\",\n                                \"hard\"\n                            ],\n                            \"type\": \"string\"\n                        },\n                        \"name\": \"difficulty\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"enum\": [\n                                \"g_easy\",\n                                \"g_medium\",\n                                \"g_hard\"\n                            ],\n                            \"type\": \"string\"\n                        },\n                        \"name\": \"genericDifficulty\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"enum\": [\n                                1,\n                                2,\n                                4,\n                                8,\n                                3\n                            ],\n                            \"type\": \"integer\"\n                        },\n                        \"name\": \"mask\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"type\": \"string\",\n                        \"name\": \"name\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"enum\": [\n                                0,\n                                1,\n                                2\n                            ],\n                            \"type\": \"integer\"\n                        },\n                        \"name\": \"securityClearance\",\n                        \"in\": \"formData\"\n                    },\n                    {\n                        \"enum\": [\n                            \"teacher\",\n                            \"student\",\n                            \"Other\"\n                        ],\n                        \"type\": \"string\",\n                        \"x-enum-comments\": {\n                            \"Other\": \"Other\",\n                            \"Student\": \"student\",\n                            \"Teacher\": \"teacher\"\n                        },\n                        \"x-enum-descriptions\": [\n                            \"teacher\",\n                            \"student\",\n                            \"Other\"\n                        ],\n                        \"x-enum-varnames\": [\n                            \"Teacher\",\n                            \"Student\",\n                            \"Other\"\n                        ],\n                        \"name\": \"type\",\n                        \"in\": \"formData\"\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\"\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"types.Class\": {\n            \"type\": \"integer\",\n            \"enum\": [\n                -1,\n                1,\n                2,\n                3,\n                4,\n                5\n            ],\n            \"x-enum-comments\": {\n                \"A\": \"AAA\",\n                \"B\": \"BBB\"\n            },\n            \"x-enum-descriptions\": [\n                \"\",\n                \"AAA\",\n                \"BBB\",\n                \"\",\n                \"\",\n                \"\"\n            ],\n            \"x-enum-varnames\": [\n                \"None\",\n                \"A\",\n                \"B\",\n                \"C\",\n                \"D\",\n                \"F\"\n            ]\n        },\n        \"types.Difficulty\": {\n            \"type\": \"string\",\n            \"enum\": [\n                \"easy\",\n                \"medium\",\n                \"hard\"\n            ],\n            \"x-enum-comments\": {\n                \"DifficultyHard\": \"This means really hard\",\n                \"Medium\": \"This one also has a comment\"\n            },\n            \"x-enum-descriptions\": [\n                \"\",\n                \"This one also has a comment\",\n                \"This means really hard\"\n            ],\n            \"x-enum-varnames\": [\n                \"Easy\",\n                \"Medium\",\n                \"DifficultyHard\"\n            ]\n        },\n        \"types.GenericDifficulty-types_Level\": {\n            \"type\": \"string\",\n            \"enum\": [\n                \"g_easy\",\n                \"g_medium\",\n                \"g_hard\"\n            ],\n            \"x-enum-comments\": {\n                \"GenericDifficultyHard\": \"This means really hard\",\n                \"GenericMedium\": \"This one also has a comment\"\n            },\n            \"x-enum-descriptions\": [\n                \"\",\n                \"This one also has a comment\",\n                \"This means really hard\"\n            ],\n            \"x-enum-varnames\": [\n                \"GenericEasy\",\n                \"GenericMedium\",\n                \"GenericDifficultyHard\"\n            ]\n        },\n        \"types.Mask\": {\n            \"type\": \"integer\",\n            \"enum\": [\n                1,\n                2,\n                4,\n                8,\n                3\n            ],\n            \"x-enum-comments\": {\n                \"Mask1\": \"Mask1\",\n                \"Mask2\": \"Mask2\",\n                \"Mask3\": \"Mask3\",\n                \"Mask4\": \"Mask4\"\n            },\n            \"x-enum-descriptions\": [\n                \"Mask1\",\n                \"Mask2\",\n                \"Mask3\",\n                \"Mask4\",\n                \"\"\n            ],\n            \"x-enum-varnames\": [\n                \"Mask1\",\n                \"Mask2\",\n                \"Mask3\",\n                \"Mask4\",\n                \"Mask5\"\n            ]\n        },\n        \"types.Person\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"class\": {\n                    \"$ref\": \"#/definitions/types.Class\"\n                },\n                \"difficulty\": {\n                    \"$ref\": \"#/definitions/types.Difficulty\"\n                },\n                \"genericDifficulty\": {\n                    \"$ref\": \"#/definitions/types.GenericDifficulty-types_Level\"\n                },\n                \"mask\": {\n                    \"$ref\": \"#/definitions/types.Mask\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                },\n                \"securityClearance\": {\n                    \"$ref\": \"#/definitions/types.SecurityClearance\"\n                },\n                \"sex\": {\n                    \"$ref\": \"#/definitions/types.Sex\"\n                },\n                \"type\": {\n                    \"$ref\": \"#/definitions/types.Type\"\n                }\n            }\n        },\n        \"types.SecurityClearance\": {\n            \"type\": \"integer\",\n            \"enum\": [\n                0,\n                1,\n                2\n            ],\n            \"x-enum-comments\": {\n                \"SecurityClearanceSensitive\": \"Name override and comment rules apply here just as above\",\n                \"SuperSecret\": \"This one has a name override and a comment\"\n            },\n            \"x-enum-descriptions\": [\n                \"\",\n                \"Name override and comment rules apply here just as above\",\n                \"This one has a name override and a comment\"\n            ],\n            \"x-enum-varnames\": [\n                \"Public\",\n                \"SecurityClearanceSensitive\",\n                \"SuperSecret\"\n            ]\n        },\n        \"types.Sex\": {\n            \"type\": \"integer\",\n            \"format\": \"int32\",\n            \"enum\": [\n                77,\n                70\n            ],\n            \"x-enum-varnames\": [\n                \"Male\",\n                \"Female\"\n            ]\n        },\n        \"types.Type\": {\n            \"type\": \"string\",\n            \"enum\": [\n                \"teacher\",\n                \"student\",\n                \"Other\"\n            ],\n            \"x-enum-comments\": {\n                \"Other\": \"Other\",\n                \"Student\": \"student\",\n                \"Teacher\": \"teacher\"\n            },\n            \"x-enum-descriptions\": [\n                \"teacher\",\n                \"student\",\n                \"Other\"\n            ],\n            \"x-enum-varnames\": [\n                \"Teacher\",\n                \"Student\",\n                \"Other\"\n            ]\n        }\n    }\n}"
  },
  {
    "path": "testdata/enums/main.go",
    "content": "package main\n\n//  @title           Swagger Example API\n//  @version         1.0\n//  @description     This is a sample server.\n//  @termsOfService  http://swagger.io/terms/\n\n//  @contact.name   API Support\n//  @contact.url    http://www.swagger.io/support\n//  @contact.email  support@swagger.io\n\n//  @license.name  Apache 2.0\n//  @license.url   http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @BasePath  /v2\nfunc main() {\n}\n"
  },
  {
    "path": "testdata/enums/types/model.go",
    "content": "package types\n\nimport (\n\t\"github.com/swaggo/swag/testdata/enums/consts\"\n)\n\ntype Class int\n\nconst (\n\tNone Class = -1\n\tA    Class = consts.Base + (iota+1-1)*2/2%100 - (1&1 | 1) + (2 ^ 2) // AAA\n\tB                                                                   /* BBB */\n\tC\n\tD = C + 1\n\tF = Class(5)\n\t//G is not enum\n\tG = H + 10\n\t//H is not enum\n\tH = 10\n\t//I is not enum\n\tI = int(F + 2)\n)\n\nconst J = 1 << uint16(I)\n\ntype Mask int\n\nconst (\n\tMask1 Mask = 0x02 << iota >> 1 // Mask1\n\tMask2                          /* Mask2 */\n\tMask3                          // Mask3\n\tMask4                          // Mask4\n\tMask5 = Mask(A + B)\n)\n\ntype Type string\n\nconst (\n\t// Teacher this line is ignored by enum comment\n\t// teacher\n\tTeacher      Type = \"teacher\"\n\tStudent      Type = \"student\" /* student */\n\tOther        Type = \"Other\"   // Other\n\tUnknown           = \"Unknown\"\n\tOtherUnknown      = string(Other + Unknown)\n)\n\ntype Sex rune\n\nconst (\n\tMale   Sex = 'M'\n\tFemale Sex = 'F'\n)\n\ntype Difficulty string\n\nconst (\n\tDifficultyEasy   Difficulty = \"easy\"   // @name Easy\n\tDifficultyMedium Difficulty = \"medium\" // @Name Medium This one also has a comment\n\tDifficultyHard   Difficulty = \"hard\"   // This means really hard\n)\n\ntype SecurityClearance int\n\nconst (\n\tSecurityClearancePublic    SecurityClearance = iota // @name Public\n\tSecurityClearanceSensitive                          // Name override and comment rules apply here just as above\n\tSecurityClearanceSecret                             // @name SuperSecret This one has a name override and a comment\n)\n\ntype (\n\tGenericDifficulty[T any] string\n\tLevel                    int\n)\n\nconst (\n\tGenericDifficultyEasy   GenericDifficulty[Level] = \"g_easy\"   // @name GenericEasy\n\tGenericDifficultyMedium GenericDifficulty[Level] = \"g_medium\" // @name GenericMedium This one also has a comment\n\tGenericDifficultyHard   GenericDifficulty[Level] = \"g_hard\"   // This means really hard\n)\n\ntype Person struct {\n\tName              string\n\tClass             Class\n\tMask              Mask\n\tType              Type\n\tSex               Sex\n\tDifficulty        Difficulty\n\tGenericDifficulty GenericDifficulty[Level]\n\tSecurityClearance SecurityClearance\n}\n\ntype PersonWithArrayEnum struct {\n\tName              string\n\tClass             []Class\n\tMask              []Mask\n\tDifficulty        []Difficulty\n\tGenericDifficulty []GenericDifficulty[Level]\n\tSecurityClearance []SecurityClearance\n\tType              Type\n}\n"
  },
  {
    "path": "testdata/error/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t. \"github.com/swaggo/swag/testdata/error/errors\"\n\t_ \"github.com/swaggo/swag/testdata/error/web\"\n)\n\n// Upload do something\n// @Summary Upload file\n// @Description Upload file\n// @ID file.upload\n// @Accept  multipart/form-data\n// @Produce  json\n// @Param   file formData file true  \"this is a test file\"\n// @Success 200 {string} string \"ok\"\n// @Failure 400 {object} web.CrossErrors \"Abort !!\"\n// @Router /file/upload [post]\nfunc Upload(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\t_ = Errors{}\n}\n"
  },
  {
    "path": "testdata/error/errors/errors.go",
    "content": "package errors\n\n// CustomInterface some interface\ntype CustomInterface interface {\n\tError() string\n}\n\n// Errors errors and interfaces\ntype Errors struct {\n\tError          error\n\tErrorInterface CustomInterface\n\tInterface      interface{}\n\tAny            any\n}\n"
  },
  {
    "path": "testdata/error/expected.json",
    "content": "{\n  \"swagger\": \"2.0\",\n  \"info\": {\n      \"description\": \"This is a sample server Petstore server.\",\n      \"title\": \"Swagger Example API\",\n      \"termsOfService\": \"http://swagger.io/terms/\",\n      \"contact\": {\n          \"name\": \"API Support\",\n          \"url\": \"http://www.swagger.io/support\",\n          \"email\": \"support@swagger.io\"\n      },\n      \"license\": {\n          \"name\": \"Apache 2.0\",\n          \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n      },\n      \"version\": \"1.0\"\n  },\n  \"host\": \"petstore.swagger.io\",\n  \"basePath\": \"/v2\",\n  \"paths\": {\n      \"/file/upload\": {\n          \"post\": {\n              \"description\": \"Upload file\",\n              \"consumes\": [\n                  \"multipart/form-data\"\n              ],\n              \"produces\": [\n                  \"application/json\"\n              ],\n              \"summary\": \"Upload file\",\n              \"operationId\": \"file.upload\",\n              \"parameters\": [\n                  {\n                      \"type\": \"file\",\n                      \"description\": \"this is a test file\",\n                      \"name\": \"file\",\n                      \"in\": \"formData\",\n                      \"required\": true\n                  }\n              ],\n              \"responses\": {\n                  \"200\": {\n                      \"description\": \"ok\",\n                      \"schema\": {\n                          \"type\": \"string\"\n                      }\n                  },\n                  \"400\": {\n                      \"description\": \"Abort !!\",\n                      \"schema\": {\n                          \"$ref\": \"#/definitions/web.CrossErrors\"\n                      }\n                  }\n              }\n          }\n      }\n  },\n  \"definitions\": {\n      \"web.CrossErrors\": {\n          \"type\": \"object\",\n          \"properties\": {\n              \"any\": {},\n              \"error\": {},\n              \"errorInterface\": {},\n              \"interface\": {}\n          }\n      }\n  }\n}"
  },
  {
    "path": "testdata/error/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/error/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\nfunc main() {\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/error/web/handler.go",
    "content": "package web\n\nimport (\n\t\"github.com/swaggo/swag/testdata/error/errors\"\n)\n\ntype CrossErrors errors.Errors\n"
  },
  {
    "path": "testdata/extensionsFail1.go",
    "content": "package main\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @description It has a lot of beautiful features.\n// @termsOfService http://swagger.io/terms/\n\n// @securitydefinitions.oauth2.accessCode OAuth2AccessCode\n// @tokenUrl https://example.com/oauth/token\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.admin Grants read and write access to administrative information\n\n// @x-google-endpoints [\"name\":\"name.endpoints.environment.cloud.goog\",\"allowCors\":true}]\n"
  },
  {
    "path": "testdata/extensionsFail2.go",
    "content": "package main\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @description It has a lot of beautiful features.\n// @termsOfService http://swagger.io/terms/\n\n// @securitydefinitions.oauth2.accessCode OAuth2AccessCode\n// @tokenUrl https://example.com/oauth/token\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.admin Grants read and write access to administrative information\n\n// @x-google-endpoints\n"
  },
  {
    "path": "testdata/external_models/external/model.go",
    "content": "package external\n\nimport \"github.com/urfave/cli/v2\"\n\ntype MyError struct {\n\tcli.Author\n}\n"
  },
  {
    "path": "testdata/external_models/main/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n)\n\n// GetExternalModels example\n// @Summary parse external models\n// @Description get string by ID\n// @ID get_external_models\n// @Accept  json\n// @Produce  json\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} http.Header \"from internal pkg\"\n// @Router /testapi/external_models [get]\nfunc GetExternalModels(w http.ResponseWriter, r *http.Request) {\n\n}\n"
  },
  {
    "path": "testdata/external_models/main/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"Parse external models.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"basePath\": \"/v1\",\n    \"paths\": {\n        \"/testapi/external_models\": {\n            \"get\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"parse external models\",\n                \"operationId\": \"get_external_models\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"from internal pkg\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/http.Header\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"http.Header\": {\n            \"type\": \"object\",\n            \"additionalProperties\": {\n                \"type\": \"array\",\n                \"items\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/external_models/main/main.go",
    "content": "package main\n\n// @title Swagger Example API\n// @version 1.0\n// @description Parse external models.\n// @BasePath /v1\nfunc main() {\n}\n"
  },
  {
    "path": "testdata/fixes-432/a/a.go",
    "content": "package a\n"
  },
  {
    "path": "testdata/fixes-432/b/b.go",
    "content": "package b\n"
  },
  {
    "path": "testdata/fixes-432/cmd/main.go",
    "content": "package main\n"
  },
  {
    "path": "testdata/format_dst/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t_ \"github.com/swaggo/swag/testdata/simple/web\"\n)\n\n// @Summary      Add a new pet to the store\n// @Description  get string by ID\n// @ID           get-string-by-int\n// @Accept       json\n// @Produce      json\n// @Param        some_id  path      int           true  \"Some ID\"  Format(int64)\n// @Param        some_id  body      web.Pet       true  \"Some ID\"\n// @Success      200      {string}  string        \"ok\"\n// @Failure      400      {object}  web.APIError  \"We need ID!!\"\n// @Failure      404      {object}  web.APIError  \"Can not find ID\"\n// @Router       /testapi/get-string-by-int/{some_id} [get]\nfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Description  get struct array by ID\n// @ID           get-struct-array-by-string\n// @Accept       json\n// @Produce      json\n// @Param        some_id   path      string        true  \"Some ID\"\n// @Param        category  query     int           true  \"Category\"  Enums(1, 2, 3)\n// @Param        offset    query     int           true  \"Offset\"    Minimum(0)    default(0)\n// @Param        limit     query     int           true  \"Limit\"     Maximum(50)   default(10)\n// @Param        q         query     string        true  \"q\"         Minlength(1)  Maxlength(50)  default(\"\")\n// @Success      200       {string}  string        \"ok\"\n// @Failure      400       {object}  web.APIError  \"We need ID!!\"\n// @Failure      404       {object}  web.APIError  \"Can not find ID\"\n// @Security     ApiKeyAuth\n// @Security     BasicAuth\n// @Security     OAuth2Application[write]\n// @Security     OAuth2Implicit[read, admin]\n// @Security     OAuth2AccessCode[read]\n// @Security     OAuth2Password[admin]\n// @Router       /testapi/get-struct-array-by-string/{some_id} [get]\nfunc GetStructArrayByString(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary      Upload file\n// @Description  Upload file\n// @ID           file.upload\n// @Accept       multipart/form-data\n// @Produce      json\n// @Param        file  formData  file          true  \"this is a test file\"\n// @Success      200   {string}  string        \"ok\"\n// @Failure      400   {object}  web.APIError  \"We need ID!!\"\n// @Failure      401   {array}   string\n// @Failure      404   {object}  web.APIError  \"Can not find ID\"\n// @Router       /file/upload [post]\nfunc Upload(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary  use Anonymous field\n// @Success  200  {object}  web.RevValue  \"ok\"\n// @Router   /AnonymousField [get]\nfunc AnonymousField() {\n\n}\n\n// @Summary  use pet2\n// @Success  200  {object}  web.Pet2  \"ok\"\n// @Router   /Pet2 [get]\nfunc Pet2() {\n\n}\n\n// @Summary  Use IndirectRecursiveTest\n// @Success  200  {object}  web.IndirectRecursiveTest\n// @Router   /IndirectRecursiveTest [get]\nfunc IndirectRecursiveTest() {\n}\n\n// @Summary  Use Tags\n// @Success  200  {object}  web.Tags\n// @Router   /Tags [get]\nfunc Tags() {\n}\n\n// @Summary  Use CrossAlias\n// @Success  200  {object}  web.CrossAlias\n// @Router   /CrossAlias [get]\nfunc CrossAlias() {\n}\n\n// @Summary  Use AnonymousStructArray\n// @Success  200  {object}  web.AnonymousStructArray\n// @Router   /AnonymousStructArray [get]\nfunc AnonymousStructArray() {\n}\n\ntype Pet3 struct {\n\tID int `json:\"id\"`\n}\n\n// @Success  200  {object}  web.Pet5a  \"ok\"\n// @Router   /GetPet5a [options]\nfunc GetPet5a() {\n\n}\n\n// @Success  200  {object}  web.Pet5b  \"ok\"\n// @Router   /GetPet5b [head]\nfunc GetPet5b() {\n\n}\n\n// @Success  200  {object}  web.Pet5c  \"ok\"\n// @Router   /GetPet5c [patch]\nfunc GetPet5c() {\n\n}\n\ntype SwagReturn []map[string]string\n\n// @Success  200  {object}  api.SwagReturn  \"ok\"\n// @Router   /GetPet6MapString [get]\nfunc GetPet6MapString() {\n\n}\n"
  },
  {
    "path": "testdata/format_dst/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/simple/api\"\n)\n\n// @title           Swagger Example API\n// @version         1.0\n// @description     This is a sample server Petstore server.\n// @termsOfService  http://swagger.io/terms/\n\n// @contact.name   API Support\n// @contact.url    http://www.swagger.io/support\n// @contact.email  support@swagger.io\n\n// @license.name  Apache 2.0\n// @license.url   http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host      petstore.swagger.io\n// @BasePath  /v2\n\n// @securityDefinitions.basic  BasicAuth\n\n// @securityDefinitions.apikey  ApiKeyAuth\n// @in                          header\n// @name                        Authorization\n\n// @securitydefinitions.oauth2.application  OAuth2Application\n// @tokenUrl                                https://example.com/oauth/token\n// @scope.write                             Grants write access\n// @scope.admin                             Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.implicit  OAuth2Implicit\n// @authorizationurl                     https://example.com/oauth/authorize\n// @scope.write                          Grants write access\n// @scope.admin                          Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.password  OAuth2Password\n// @tokenUrl                             https://example.com/oauth/token\n// @scope.read                           Grants read access\n// @scope.write                          Grants write access\n// @scope.admin                          Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.accessCode  OAuth2AccessCode\n// @tokenUrl                               https://example.com/oauth/token\n// @authorizationurl                       https://example.com/oauth/authorize\n// @scope.admin                            Grants read and write access to administrative information\nfunc main() {\n\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\thttp.HandleFunc(\"/testapi/get-struct-array-by-string/\", api.GetStructArrayByString)\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/format_dst/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n\n\t\"github.com/gofrs/uuid\"\n\t\"github.com/shopspring/decimal\"\n\n\t\"github.com/swaggo/swag/testdata/simple/cross\"\n)\n\ntype Pet struct {\n\tID       int `json:\"id\" example:\"1\" format:\"int64\" readonly:\"true\"`\n\tCategory struct {\n\t\tID            int      `json:\"id\" example:\"1\"`\n\t\tName          string   `json:\"name\" example:\"category_name\"`\n\t\tPhotoUrls     []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\" format:\"url\"`\n\t\tSmallCategory struct {\n\t\t\tID        int      `json:\"id\" example:\"1\"`\n\t\t\tName      string   `json:\"name\" example:\"detail_category_name\" binding:\"required\" minLength:\"4\" maxLength:\"16\"`\n\t\t\tPhotoUrls []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\t\t} `json:\"small_category\"`\n\t} `json:\"category\"`\n\tName      string            `json:\"name\" example:\"poti\" binding:\"required\"`\n\tPhotoUrls []string          `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\" binding:\"required\"`\n\tTags      []Tag             `json:\"tags\"`\n\tPets      *[]Pet2           `json:\"pets\"`\n\tPets2     []*Pet2           `json:\"pets2\"`\n\tStatus    string            `json:\"status\" enums:\"healthy,ill\"`\n\tPrice     float32           `json:\"price\" example:\"3.25\" minimum:\"1.0\" maximum:\"1000\" multipleOf:\"0.01\"`\n\tIsAlive   bool              `json:\"is_alive\" example:\"true\" default:\"true\"`\n\tData      interface{}       `json:\"data\"`\n\tHidden    string            `json:\"-\"`\n\tUUID      uuid.UUID         `json:\"uuid\"`\n\tDecimal   decimal.Decimal   `json:\"decimal\"`\n\tIntArray  []int             `json:\"int_array\" example:\"1,2\"`\n\tStringMap map[string]string `json:\"string_map\" example:\"key1:value,key2:value2\"`\n\tEnumArray []int             `json:\"enum_array\" enums:\"1,2,3,5,7\"`\n}\n\ntype Tag struct {\n\tID   int    `json:\"id\" format:\"int64\"`\n\tName string `json:\"name\"`\n\tPets []Pet  `json:\"pets\"`\n}\n\ntype Tags []*Tag\n\ntype AnonymousStructArray []struct {\n\tFoo string `json:\"foo\"`\n}\n\ntype CrossAlias cross.Cross\n\ntype Pet2 struct {\n\tID         int        `json:\"id\"`\n\tMiddleName *string    `json:\"middlename\" extensions:\"x-nullable,x-abc=def,!x-omitempty\"`\n\tDeletedAt  *time.Time `json:\"deleted_at\"`\n}\n\ntype IndirectRecursiveTest struct {\n\tTags []Tag\n}\n\ntype APIError struct {\n\tErrorCode    int\n\tErrorMessage string\n\tCreatedAt    time.Time\n}\n\ntype RevValueBase struct {\n\tStatus bool `json:\"Status\"`\n\n\tErr int32 `json:\"Err,omitempty\"`\n}\ntype RevValue struct {\n\tRevValueBase `json:\"rev_value_base\"`\n\n\tData    int           `json:\"Data\"`\n\tCross   cross.Cross   `json:\"cross\"`\n\tCrosses []cross.Cross `json:\"crosses\"`\n}\n\n// Below we have Pet5b as base type and Pet5a and Pet5c both have Pet5b as anonymous field, inheriting it's properties\n// By using these names we ensure that our test will fill if the order of parsing matters at all\n\ntype Pet5a struct {\n\t*Pet5b\n\tOdd bool `json:\"odd\" binding:\"required\"`\n}\n\ntype Pet5b struct {\n\tName string `json:\"name\" binding:\"required\"`\n}\n\ntype Pet5c struct {\n\t*Pet5b\n\tOdd bool `json:\"odd\" binding:\"required\"`\n}\n\n// @testFunc  a Func\n// @test2     das A\nfunc testFunc() {\n\n}\n"
  },
  {
    "path": "testdata/format_empty/empty.go",
    "content": "package main\n\n// nothing\n"
  },
  {
    "path": "testdata/format_src/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t_ \"github.com/swaggo/swag/testdata/simple/web\"\n)\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @ID get-string-by-int\n// @Accept  json\n// @Produce  json\n// @Param   some_id      path   int     true  \"Some ID\" Format(int64)\n// @Param   some_id      body web.Pet true  \"Some ID\"\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /testapi/get-string-by-int/{some_id} [get]\nfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Description get struct array by ID\n// @ID get-struct-array-by-string\n// @Accept  json\n// @Produce  json\n// @Param some_id path string true \"Some ID\"\n// @Param category query int true \"Category\" Enums(1, 2, 3)\n// @Param offset query int true \"Offset\" Minimum(0) default(0)\n// @Param limit query int true \"Limit\" Maximum(50) default(10)\n// @Param q query string true \"q\" Minlength(1) Maxlength(50) default(\"\")\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Security ApiKeyAuth\n// @Security BasicAuth\n// @Security OAuth2Application[write]\n// @Security OAuth2Implicit[read, admin]\n// @Security OAuth2AccessCode[read]\n// @Security OAuth2Password[admin]\n// @Router /testapi/get-struct-array-by-string/{some_id} [get]\nfunc GetStructArrayByString(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary Upload file\n// @Description Upload file\n// @ID file.upload\n// @Accept  multipart/form-data\n// @Produce  json\n// @Param   file formData file true  \"this is a test file\"\n// @Success 200 {string} string \"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 401 {array} string\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /file/upload [post]\nfunc Upload(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary use Anonymous field\n// @Success 200 {object} web.RevValue \"ok\"\n// @Router /AnonymousField [get]\nfunc AnonymousField() {\n\n}\n\n// @Summary use pet2\n// @Success 200 {object} web.Pet2 \"ok\"\n// @Router /Pet2 [get]\nfunc Pet2() {\n\n}\n\n// @Summary Use IndirectRecursiveTest\n// @Success 200 {object} web.IndirectRecursiveTest\n// @Router /IndirectRecursiveTest [get]\nfunc IndirectRecursiveTest() {\n}\n\n// @Summary Use Tags\n// @Success 200 {object} web.Tags\n// @Router /Tags [get]\nfunc Tags() {\n}\n\n// @Summary Use CrossAlias\n// @Success 200 {object} web.CrossAlias\n// @Router /CrossAlias [get]\nfunc CrossAlias() {\n}\n\n// @Summary Use AnonymousStructArray\n// @Success 200 {object} web.AnonymousStructArray\n// @Router /AnonymousStructArray [get]\nfunc AnonymousStructArray() {\n}\n\ntype Pet3 struct {\n\tID int `json:\"id\"`\n}\n\n// @Success 200 {object} web.Pet5a \"ok\"\n// @Router /GetPet5a [options]\nfunc GetPet5a() {\n\n}\n\n// @Success 200 {object} web.Pet5b \"ok\"\n// @Router /GetPet5b [head]\nfunc GetPet5b() {\n\n}\n\n// @Success 200 {object} web.Pet5c \"ok\"\n// @Router /GetPet5c [patch]\nfunc GetPet5c() {\n\n}\n\ntype SwagReturn []map[string]string\n\n// @Success 200 {object}  api.SwagReturn\t\"ok\"\n// @Router /GetPet6MapString [get]\nfunc GetPet6MapString() {\n\n}\n"
  },
  {
    "path": "testdata/format_src/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/simple/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\n// @securityDefinitions.basic BasicAuth\n\n// @securityDefinitions.apikey ApiKeyAuth\n// @in header\n// @name Authorization\n\n// @securitydefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.implicit OAuth2Implicit\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.password OAuth2Password\n// @tokenUrl https://example.com/oauth/token\n// @scope.read Grants read access\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.accessCode OAuth2AccessCode\n// @tokenUrl https://example.com/oauth/token\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.admin Grants read and write access to administrative information\nfunc main() {\n\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\thttp.HandleFunc(\"/testapi/get-struct-array-by-string/\", api.GetStructArrayByString)\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/format_src/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n\n\t\"github.com/gofrs/uuid\"\n\t\"github.com/shopspring/decimal\"\n\n\t\"github.com/swaggo/swag/testdata/simple/cross\"\n)\n\ntype Pet struct {\n\tID       int `json:\"id\" example:\"1\" format:\"int64\" readonly:\"true\"`\n\tCategory struct {\n\t\tID            int      `json:\"id\" example:\"1\"`\n\t\tName          string   `json:\"name\" example:\"category_name\"`\n\t\tPhotoUrls     []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\" format:\"url\"`\n\t\tSmallCategory struct {\n\t\t\tID        int      `json:\"id\" example:\"1\"`\n\t\t\tName      string   `json:\"name\" example:\"detail_category_name\" binding:\"required\" minLength:\"4\" maxLength:\"16\"`\n\t\t\tPhotoUrls []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\t\t} `json:\"small_category\"`\n\t} `json:\"category\"`\n\tName      string            `json:\"name\" example:\"poti\" binding:\"required\"`\n\tPhotoUrls []string          `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\" binding:\"required\"`\n\tTags      []Tag             `json:\"tags\"`\n\tPets      *[]Pet2           `json:\"pets\"`\n\tPets2     []*Pet2           `json:\"pets2\"`\n\tStatus    string            `json:\"status\" enums:\"healthy,ill\"`\n\tPrice     float32           `json:\"price\" example:\"3.25\" minimum:\"1.0\" maximum:\"1000\" multipleOf:\"0.01\"`\n\tIsAlive   bool              `json:\"is_alive\" example:\"true\" default:\"true\"`\n\tData      interface{}       `json:\"data\"`\n\tHidden    string            `json:\"-\"`\n\tUUID      uuid.UUID         `json:\"uuid\"`\n\tDecimal   decimal.Decimal   `json:\"decimal\"`\n\tIntArray  []int             `json:\"int_array\" example:\"1,2\"`\n\tStringMap map[string]string `json:\"string_map\" example:\"key1:value,key2:value2\"`\n\tEnumArray []int             `json:\"enum_array\" enums:\"1,2,3,5,7\"`\n}\n\ntype Tag struct {\n\tID   int    `json:\"id\" format:\"int64\"`\n\tName string `json:\"name\"`\n\tPets []Pet  `json:\"pets\"`\n}\n\ntype Tags []*Tag\n\ntype AnonymousStructArray []struct {\n\tFoo string `json:\"foo\"`\n}\n\ntype CrossAlias cross.Cross\n\ntype Pet2 struct {\n\tID         int        `json:\"id\"`\n\tMiddleName *string    `json:\"middlename\" extensions:\"x-nullable,x-abc=def,!x-omitempty\"`\n\tDeletedAt  *time.Time `json:\"deleted_at\"`\n}\n\ntype IndirectRecursiveTest struct {\n\tTags []Tag\n}\n\ntype APIError struct {\n\tErrorCode    int\n\tErrorMessage string\n\tCreatedAt    time.Time\n}\n\ntype RevValueBase struct {\n\tStatus bool `json:\"Status\"`\n\n\tErr int32 `json:\"Err,omitempty\"`\n}\ntype RevValue struct {\n\tRevValueBase `json:\"rev_value_base\"`\n\n\tData    int           `json:\"Data\"`\n\tCross   cross.Cross   `json:\"cross\"`\n\tCrosses []cross.Cross `json:\"crosses\"`\n}\n\n// Below we have Pet5b as base type and Pet5a and Pet5c both have Pet5b as anonymous field, inheriting it's properties\n// By using these names we ensure that our test will fill if the order of parsing matters at all\n\ntype Pet5a struct {\n\t*Pet5b\n\tOdd bool `json:\"odd\" binding:\"required\"`\n}\n\ntype Pet5b struct {\n\tName string `json:\"name\" binding:\"required\"`\n}\n\ntype Pet5c struct {\n\t*Pet5b\n\tOdd bool `json:\"odd\" binding:\"required\"`\n}\n\n// @testFunc a Func\n// @test2 das A\nfunc testFunc() {\n\n}\n"
  },
  {
    "path": "testdata/format_test/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t_ \"github.com/swaggo/swag/testdata/simple/web\"\n)\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @ID get-string-by-int\n// @Accept  json\n// @Produce  json\n// @Param   some_id      path   int     true  \"Some ID\" Format(int64)\n// @Param   some_id      body web.Pet true  \"Some ID\"\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /testapi/get-string-by-int/{some_id} [get]\nfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Description get struct array by ID\n// @ID get-struct-array-by-string\n// @Accept  json\n// @Produce  json\n// @Param some_id path string true \"Some ID\"\n// @Param category query int true \"Category\" Enums(1, 2, 3)\n// @Param offset query int true \"Offset\" Minimum(0) default(0)\n// @Param limit query int true \"Limit\" Maximum(50) default(10)\n// @Param q query string true \"q\" Minlength(1) Maxlength(50) default(\"\")\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Security ApiKeyAuth\n// @Security BasicAuth\n// @Security OAuth2Application[write]\n// @Security OAuth2Implicit[read, admin]\n// @Security OAuth2AccessCode[read]\n// @Security OAuth2Password[admin]\n// @Router /testapi/get-struct-array-by-string/{some_id} [get]\nfunc GetStructArrayByString(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary Upload file\n// @Description Upload file\n// @ID file.upload\n// @Accept  multipart/form-data\n// @Produce  json\n// @Param   file formData file true  \"this is a test file\"\n// @Success 200 {string} string \"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 401 {array} string\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /file/upload [post]\nfunc Upload(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary use Anonymous field\n// @Success 200 {object} web.RevValue \"ok\"\n// @Router /AnonymousField [get]\nfunc AnonymousField() {\n\n}\n\n// @Summary use pet2\n// @Success 200 {object} web.Pet2 \"ok\"\n// @Router /Pet2 [get]\nfunc Pet2() {\n\n}\n\n// @Summary Use IndirectRecursiveTest\n// @Success 200 {object} web.IndirectRecursiveTest\n// @Router /IndirectRecursiveTest [get]\nfunc IndirectRecursiveTest() {\n}\n\n// @Summary Use Tags\n// @Success 200 {object} web.Tags\n// @Router /Tags [get]\nfunc Tags() {\n}\n\n// @Summary Use CrossAlias\n// @Success 200 {object} web.CrossAlias\n// @Router /CrossAlias [get]\nfunc CrossAlias() {\n}\n\n// @Summary Use AnonymousStructArray\n// @Success 200 {object} web.AnonymousStructArray\n// @Router /AnonymousStructArray [get]\nfunc AnonymousStructArray() {\n}\n\ntype Pet3 struct {\n\tID int `json:\"id\"`\n}\n\n// @Success 200 {object} web.Pet5a \"ok\"\n// @Router /GetPet5a [options]\nfunc GetPet5a() {\n\n}\n\n// @Success 200 {object} web.Pet5b \"ok\"\n// @Router /GetPet5b [head]\nfunc GetPet5b() {\n\n}\n\n// @Success 200 {object} web.Pet5c \"ok\"\n// @Router /GetPet5c [patch]\nfunc GetPet5c() {\n\n}\n\ntype SwagReturn []map[string]string\n\n// @Success 200 {object}  api.SwagReturn\t\"ok\"\n// @Router /GetPet6MapString [get]\nfunc GetPet6MapString() {\n\n}\n"
  },
  {
    "path": "testdata/format_test/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/simple/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\n// @securityDefinitions.basic BasicAuth\n\n// @securityDefinitions.apikey ApiKeyAuth\n// @in header\n// @name Authorization\n\n// @securitydefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.implicit OAuth2Implicit\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.password OAuth2Password\n// @tokenUrl https://example.com/oauth/token\n// @scope.read Grants read access\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.accessCode OAuth2AccessCode\n// @tokenUrl https://example.com/oauth/token\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.admin Grants read and write access to administrative information\nfunc main() {\n\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\thttp.HandleFunc(\"/testapi/get-struct-array-by-string/\", api.GetStructArrayByString)\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/format_test/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n\n\t\"github.com/gofrs/uuid\"\n\t\"github.com/shopspring/decimal\"\n\n\t\"github.com/swaggo/swag/testdata/simple/cross\"\n)\n\ntype Pet struct {\n\tID       int `json:\"id\" example:\"1\" format:\"int64\" readonly:\"true\"`\n\tCategory struct {\n\t\tID            int      `json:\"id\" example:\"1\"`\n\t\tName          string   `json:\"name\" example:\"category_name\"`\n\t\tPhotoUrls     []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\" format:\"url\"`\n\t\tSmallCategory struct {\n\t\t\tID        int      `json:\"id\" example:\"1\"`\n\t\t\tName      string   `json:\"name\" example:\"detail_category_name\" binding:\"required\" minLength:\"4\" maxLength:\"16\"`\n\t\t\tPhotoUrls []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\t\t} `json:\"small_category\"`\n\t} `json:\"category\"`\n\tName      string            `json:\"name\" example:\"poti\" binding:\"required\"`\n\tPhotoUrls []string          `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\" binding:\"required\"`\n\tTags      []Tag             `json:\"tags\"`\n\tPets      *[]Pet2           `json:\"pets\"`\n\tPets2     []*Pet2           `json:\"pets2\"`\n\tStatus    string            `json:\"status\" enums:\"healthy,ill\"`\n\tPrice     float32           `json:\"price\" example:\"3.25\" minimum:\"1.0\" maximum:\"1000\" multipleOf:\"0.01\"`\n\tIsAlive   bool              `json:\"is_alive\" example:\"true\" default:\"true\"`\n\tData      interface{}       `json:\"data\"`\n\tHidden    string            `json:\"-\"`\n\tUUID      uuid.UUID         `json:\"uuid\"`\n\tDecimal   decimal.Decimal   `json:\"decimal\"`\n\tIntArray  []int             `json:\"int_array\" example:\"1,2\"`\n\tStringMap map[string]string `json:\"string_map\" example:\"key1:value,key2:value2\"`\n\tEnumArray []int             `json:\"enum_array\" enums:\"1,2,3,5,7\"`\n}\n\ntype Tag struct {\n\tID   int    `json:\"id\" format:\"int64\"`\n\tName string `json:\"name\"`\n\tPets []Pet  `json:\"pets\"`\n}\n\ntype Tags []*Tag\n\ntype AnonymousStructArray []struct {\n\tFoo string `json:\"foo\"`\n}\n\ntype CrossAlias cross.Cross\n\ntype Pet2 struct {\n\tID         int        `json:\"id\"`\n\tMiddleName *string    `json:\"middlename\" extensions:\"x-nullable,x-abc=def,!x-omitempty\"`\n\tDeletedAt  *time.Time `json:\"deleted_at\"`\n}\n\ntype IndirectRecursiveTest struct {\n\tTags []Tag\n}\n\ntype APIError struct {\n\tErrorCode    int\n\tErrorMessage string\n\tCreatedAt    time.Time\n}\n\ntype RevValueBase struct {\n\tStatus bool `json:\"Status\"`\n\n\tErr int32 `json:\"Err,omitempty\"`\n}\ntype RevValue struct {\n\tRevValueBase `json:\"rev_value_base\"`\n\n\tData    int           `json:\"Data\"`\n\tCross   cross.Cross   `json:\"cross\"`\n\tCrosses []cross.Cross `json:\"crosses\"`\n}\n\n// Below we have Pet5b as base type and Pet5a and Pet5c both have Pet5b as anonymous field, inheriting it's properties\n// By using these names we ensure that our test will fill if the order of parsing matters at all\n\ntype Pet5a struct {\n\t*Pet5b\n\tOdd bool `json:\"odd\" binding:\"required\"`\n}\n\ntype Pet5b struct {\n\tName string `json:\"name\" binding:\"required\"`\n}\n\ntype Pet5c struct {\n\t*Pet5b\n\tOdd bool `json:\"odd\" binding:\"required\"`\n}\n\n// @testFunc a Func\n// @test2 das A\nfunc testFunc() {\n\n}\n"
  },
  {
    "path": "testdata/generics_arrays/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_arrays/types\"\n\t\"github.com/swaggo/swag/testdata/generics_arrays/web\"\n)\n\n// @Summary List Posts\n// @Description Get All of the Posts\n// @Accept  json\n// @Produce  json\n// @Param   data        body   web.GenericListBody[types.Post]    true  \"Some ID\"\n// @Success 200 {object} web.GenericListResponse[types.Post]\n// @Success 222 {object} web.GenericListResponseMulti[types.Post, types.Post]\n// @Router /posts [get]\nfunc GetPosts(w http.ResponseWriter, r *http.Request) {\n\t_ = web.GenericListResponseMulti[types.Post, types.Post]{}\n}\n\n// @Summary Add new pets to the store\n// @Description get string by ID\n// @Accept  json\n// @Produce  json\n// @Param   data        body   web.GenericListBodyMulti[types.Post, types.Post] true  \"Some ID\"\n// @Success 200 {object} web.GenericListResponse[types.Post]\n// @Success 222 {object} web.GenericListResponseMulti[types.Post, types.Post]\n// @Router /posts-multi [get]\nfunc GetPostMulti(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\t_ = web.GenericListResponseMulti[types.Post, types.Post]{}\n}\n\n// @Summary Add new pets to the store\n// @Description get string by ID\n// @Accept  json\n// @Produce  json\n// @Param   data        body   web.GenericListBodyMulti[types.Post, []types.Post] true  \"Some ID\"\n// @Success 200 {object} web.GenericListResponse[[]types.Post]\n// @Success 222 {object} web.GenericListResponseMulti[types.Post, []types.Post]\n// @Router /posts-multis [get]\nfunc GetPostArray(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\t_ = web.GenericListResponseMulti[types.Post, []types.Post]{}\n}\n"
  },
  {
    "path": "testdata/generics_arrays/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:4000\",\n    \"basePath\": \"/api\",\n    \"paths\": {\n        \"/posts\": {\n            \"get\": {\n                \"description\": \"Get All of the Posts\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"List Posts\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericListBody-types_Post\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericListResponse-types_Post\"\n                        }\n                    },\n                    \"222\": {\n                        \"description\": \"\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericListResponseMulti-types_Post-types_Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/posts-multi\": {\n            \"get\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add new pets to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericListBodyMulti-types_Post-types_Post\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericListResponse-types_Post\"\n                        }\n                    },\n                    \"222\": {\n                        \"description\": \"\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericListResponseMulti-types_Post-types_Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/posts-multis\": {\n            \"get\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add new pets to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericListBodyMulti-types_Post-array_types_Post\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericListResponse-array_types_Post\"\n                        }\n                    },\n                    \"222\": {\n                        \"description\": \"\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericListResponseMulti-types_Post-array_types_Post\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"types.Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"@uri\": {\n                    \"type\": \"string\"\n                },\n                \"data\": {\n                    \"description\": \"Post data\",\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"name\": {\n                            \"description\": \"Post tag\",\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"string\"\n                            }\n                        }\n                    }\n                },\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\",\n                    \"example\": 1\n                },\n                \"name\": {\n                    \"description\": \"Post name\",\n                    \"type\": \"string\",\n                    \"example\": \"poti\"\n                }\n            }\n        },\n        \"web.GenericListBody-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                }\n            }\n        },\n        \"web.GenericListBodyMulti-types_Post-array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"meta\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"web.GenericListBodyMulti-types_Post-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"meta\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                }\n            }\n        },\n        \"web.GenericListResponse-array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of some other stuff\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericListResponse-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of some other stuff\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericListResponseMulti-types_Post-array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemsOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of the things\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericListResponseMulti-types_Post-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemsOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of the things\",\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/generics_arrays/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_arrays/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @host localhost:4000\n// @basePath /api\nfunc main() {\n\thttp.HandleFunc(\"/posts/\", api.GetPosts)\n\thttp.HandleFunc(\"/posts-multi/\", api.GetPostMulti)\n\thttp.HandleFunc(\"/posts-multis/\", api.GetPostArray)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/generics_arrays/types/post.go",
    "content": "package types\n\ntype APIBase struct {\n\tAPIUrl string `json:\"@uri,omitempty\"`\n\tID     int    `json:\"id\" example:\"1\" format:\"int64\"`\n}\n\ntype Post struct {\n\tAPIBase\n\t// Post name\n\tName string `json:\"name\" example:\"poti\"`\n\t// Post data\n\tData struct {\n\t\t// Post tag\n\t\tTag []string `json:\"name\"`\n\t} `json:\"data\"`\n}\n"
  },
  {
    "path": "testdata/generics_arrays/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n)\n\ntype GenericListBody[T any] struct {\n\tData []T\n}\n\ntype GenericListBodyMulti[T any, X any] struct {\n\tData []T\n\tMeta []X\n}\n\n// GenericListResponse[T]\n// @Description Some Generic List Response\ntype GenericListResponse[T any] struct {\n\t// Items from the list response\n\tItems []T\n\t// Status of some other stuff\n\tStatus string\n}\n\n// GenericListResponseMulti[T, X]\n// @Description this contains a few things\ntype GenericListResponseMulti[T any, X any] struct {\n\t// ItemsOne is the first thing\n\tItemsOne []T\n\t// ItemsTwo is the second thing\n\tItemsTwo []X\n\n\t// Status of the things\n\tStatus string\n}\n\n// APIError\n// @Description API error\n// @Description with information about it\n// Other some summary\ntype APIError struct {\n\t// Error an Api error\n\tError string // Error this is Line comment\n\t// Error `number` tick comment\n\tErrorNo   int64\n\tErrorCtx  string    // Error `context` tick comment\n\tCreatedAt time.Time // Error time\n}\n"
  },
  {
    "path": "testdata/generics_basic/.swaggo",
    "content": "replace types.Field[string] string\nreplace types.DoubleField[string,string] []string\nreplace types.TrippleField[string,string] [][]string"
  },
  {
    "path": "testdata/generics_basic/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_basic/types\"\n\t\"github.com/swaggo/swag/testdata/generics_basic/web\"\n)\n\ntype Response[T any, X any] struct {\n\tData T\n\tMeta X\n\n\tStatus string\n}\n\ntype Response2[T, X any, Y any] struct {\n\tData T\n\tMeta X\n\n\tStatus Y\n}\n\ntype StringStruct struct {\n\tData string\n}\n\ntype Foo = web.GenericResponseMulti[types.Post, types.Post]\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @Accept  json\n// @Produce  json\n// @Param   data        body   web.GenericBody[types.Post]    true  \"Some ID\"\n// @Success 200 {object} web.GenericResponse[types.Post]\n// @Success 201 {object} web.GenericResponse[types.Hello]\n// @Success 202 {object} web.GenericResponse[types.Field[string]]\n// @Success 203 {object} web.GenericResponse[types.Field[int]]\n// @Success 204 {object} Response[string, types.Field[int]]\n// @Success 205 {object} Response[StringStruct, types.Field[int]]\n// @Success 206 {object} Response2[string, types.Field[int],string]\n// @Success 207 {object} Response[[]map[string]string, map[string][]types.Field[int]]\n// @Success 222 {object} web.GenericResponseMulti[types.Post, types.Post]\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /posts/ [post]\nfunc GetPost(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\t_ = web.GenericResponse[types.Post]{}\n}\n\n// @Summary Add new pets to the store\n// @Description get string by ID\n// @Accept  json\n// @Produce  json\n// @Param   data\tbody\tweb.GenericBodyMulti[types.Post, types.Post]\ttrue\t\"Some ID\"\n// @Success 200 {object} web.GenericResponse[types.Post]\n// @Success 201 {object} web.GenericResponse[types.Hello]\n// @Success 202 {object} web.GenericResponse[types.Field[string]]\n// @Success 203 {object} Foo\n// @Success 222 {object} web.GenericResponseMulti[types.Post, types.Post]\n// @Router /posts-multi/ [post]\nfunc GetPostMulti(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\t_ = web.GenericResponse[types.Post]{}\n}\n\n// @Summary Add new pets to the store\n// @Description get string by ID\n// @Accept  json\n// @Produce  json\n// @Param   data\tbody\tweb.GenericBodyMulti[[]types.Post, [][]types.Post]\ttrue\t\"Some ID\"\n// @Success 200 {object} web.GenericResponse[[]types.Post]\n// @Success 201 {object} web.GenericResponse[[]types.Hello]\n// @Success 222 {object} web.GenericResponseMulti[[]types.Post, [][]types.Post]\n// @Router /posts-multis/ [post]\nfunc GetPostArray(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\t_ = web.GenericResponse[types.Post]{}\n}\n"
  },
  {
    "path": "testdata/generics_basic/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:4000\",\n    \"basePath\": \"/api\",\n    \"paths\": {\n        \"/posts-multi/\": {\n            \"post\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add new pets to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericBodyMulti-types_Post-types_Post\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponse-types_Post\"\n                        }\n                    },\n                    \"201\": {\n                        \"description\": \"Created\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponse-types_Hello\"\n                        }\n                    },\n                    \"202\": {\n                        \"description\": \"Accepted\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponse-types_Field-string\"\n                        }\n                    },\n                    \"203\": {\n                        \"description\": \"Non-Authoritative Information\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.Foo\"\n                        }\n                    },\n                    \"222\": {\n                        \"description\": \"\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponseMulti-types_Post-types_Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/posts-multis/\": {\n            \"post\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add new pets to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericBodyMulti-array_types_Post-array_array_types_Post\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponse-array_types_Post\"\n                        }\n                    },\n                    \"201\": {\n                        \"description\": \"Created\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponse-array_types_Hello\"\n                        }\n                    },\n                    \"222\": {\n                        \"description\": \"\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponseMulti-array_types_Post-array_array_types_Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/posts/\": {\n            \"post\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add a new pet to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericBody-types_Post\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponse-types_Post\"\n                        }\n                    },\n                    \"201\": {\n                        \"description\": \"Created\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponse-types_Hello\"\n                        }\n                    },\n                    \"202\": {\n                        \"description\": \"Accepted\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponse-types_Field-string\"\n                        }\n                    },\n                    \"203\": {\n                        \"description\": \"Non-Authoritative Information\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponse-types_Field-int\"\n                        }\n                    },\n                    \"204\": {\n                        \"description\": \"No Content\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.Response-string-types_Field-int\"\n                        }\n                    },\n                    \"205\": {\n                        \"description\": \"Reset Content\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.Response-api_StringStruct-types_Field-int\"\n                        }\n                    },\n                    \"206\": {\n                        \"description\": \"Partial Content\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.Response2-string-types_Field-int-string\"\n                        }\n                    },\n                    \"207\": {\n                        \"description\": \"Multi-Status\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.Response-array_map_string_string-map_string_array_types_Field-int\"\n                        }\n                    },\n                    \"222\": {\n                        \"description\": \"\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericResponseMulti-types_Post-types_Post\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"api.Foo\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/types.Post\"\n                },\n                \"meta\": {\n                    \"$ref\": \"#/definitions/types.Post\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.Response-api_StringStruct-types_Field-int\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/api.StringStruct\"\n                },\n                \"meta\": {\n                    \"$ref\": \"#/definitions/types.Field-int\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.Response-array_map_string_string-map_string_array_types_Field-int\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"object\",\n                        \"additionalProperties\": {\n                            \"type\": \"string\"\n                        }\n                    }\n                },\n                \"meta\": {\n                    \"$ref\": \"#/definitions/map_string_array_types.Field-int\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.Response-string-types_Field-int\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"string\"\n                },\n                \"meta\": {\n                    \"$ref\": \"#/definitions/types.Field-int\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.Response2-string-types_Field-int-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"string\"\n                },\n                \"meta\": {\n                    \"$ref\": \"#/definitions/types.Field-int\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.StringStruct\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"map_string_array_types.Field-int\": {\n            \"type\": \"object\",\n            \"additionalProperties\": {\n                \"type\": \"array\",\n                \"items\": {\n                    \"$ref\": \"#/definitions/types.Field-int\"\n                }\n            }\n        },\n        \"types.Field-int\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"value\": {\n                    \"type\": \"integer\"\n                }\n            }\n        },\n        \"types.Field-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"value\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.Hello\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"arrayField\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    }\n                },\n                \"mapField\": {\n                    \"$ref\": \"#/definitions/types.MapField-string-float64\"\n                },\n                \"mapFieldNestedStruct\": {\n                    \"$ref\": \"#/definitions/types.MapFieldNestedStruct-string\"\n                },\n                \"myNewArrayField\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    }\n                },\n                \"myNewField\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    }\n                },\n                \"myStringField1\": {\n                    \"type\": \"string\"\n                },\n                \"myStringField2\": {\n                    \"type\": \"string\"\n                },\n                \"originArrayField\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    }\n                },\n                \"originMapField\": {\n                    \"type\": \"object\",\n                    \"additionalProperties\": {\n                        \"type\": \"number\",\n                        \"format\": \"float64\"\n                    }\n                }\n            }\n        },\n        \"types.MapField-string-float64\": {\n            \"type\": \"object\",\n            \"additionalProperties\": {\n                \"type\": \"number\",\n                \"format\": \"float64\"\n            }\n        },\n        \"types.MapFieldNestedStruct-string\": {\n            \"type\": \"object\",\n            \"additionalProperties\": {\n                \"$ref\": \"#/definitions/types.MapFieldValue\"\n            }\n        },\n        \"types.MapFieldValue\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"f\": {\n                    \"type\": \"number\",\n                    \"format\": \"float64\"\n                },\n                \"s\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"@uri\": {\n                    \"type\": \"string\"\n                },\n                \"data\": {\n                    \"description\": \"Post data\",\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"name\": {\n                            \"description\": \"Post tag\",\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"string\"\n                            }\n                        }\n                    }\n                },\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\",\n                    \"example\": 1\n                },\n                \"name\": {\n                    \"description\": \"Post name\",\n                    \"type\": \"string\",\n                    \"example\": \"poti\"\n                }\n            }\n        },\n        \"web.APIError\": {\n            \"description\": \"API error with information about it\",\n            \"type\": \"object\",\n            \"properties\": {\n                \"createdAt\": {\n                    \"description\": \"Error time\",\n                    \"type\": \"string\"\n                },\n                \"error\": {\n                    \"description\": \"Error an Api error\",\n                    \"type\": \"string\"\n                },\n                \"errorCtx\": {\n                    \"description\": \"Error `context` tick comment\",\n                    \"type\": \"string\"\n                },\n                \"errorNo\": {\n                    \"description\": \"Error `number` tick comment\",\n                    \"type\": \"integer\",\n                    \"format\": \"int64\"\n                }\n            }\n        },\n        \"web.GenericBody-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/types.Post\"\n                }\n            }\n        },\n        \"web.GenericBodyMulti-array_types_Post-array_array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"meta\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"web.GenericBodyMulti-types_Post-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/types.Post\"\n                },\n                \"meta\": {\n                    \"$ref\": \"#/definitions/types.Post\"\n                }\n            }\n        },\n        \"web.GenericResponse-array_types_Hello\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Hello\"\n                    }\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericResponse-array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericResponse-types_Field-int\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/types.Field-int\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericResponse-types_Field-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/types.Field-string\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericResponse-types_Hello\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/types.Hello\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericResponse-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/types.Post\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericResponseMulti-array_types_Post-array_array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"meta\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    }\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericResponseMulti-types_Post-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/types.Post\"\n                },\n                \"meta\": {\n                    \"$ref\": \"#/definitions/types.Post\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/generics_basic/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_basic/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @host localhost:4000\n// @basePath /api\nfunc main() {\n\thttp.HandleFunc(\"/posts/\", api.GetPost)\n\thttp.HandleFunc(\"/posts-multi/\", api.GetPostMulti)\n\thttp.HandleFunc(\"/posts-multis/\", api.GetPostArray)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/generics_basic/types/post.go",
    "content": "package types\n\ntype APIBase struct {\n\tAPIUrl string `json:\"@uri,omitempty\"`\n\tID     int    `json:\"id\" example:\"1\" format:\"int64\"`\n}\n\ntype Post struct {\n\tAPIBase\n\tID int `json:\"id\" example:\"1\" format:\"int64\"`\n\t// Post name\n\tName string `json:\"name\" example:\"poti\"`\n\t// Post data\n\tData struct {\n\t\t// Post tag\n\t\tTag []string `json:\"name\"`\n\t} `json:\"data\"`\n}\n"
  },
  {
    "path": "testdata/generics_basic/types/string.go",
    "content": "package types\n\ntype Field[T any] struct {\n\tValue T\n}\n\ntype DoubleField[T1 any, T2 any] struct {\n\tValue1 T1\n\tValue2 T2\n}\n\ntype TrippleField[T1 any, T2 any] struct {\n\tValue1 T1\n\tValue2 T2\n}\n\ntype ArrayField[T any] []T\ntype MapField[K comparable, V any] map[K]V\ntype MapFieldValue struct {\n\tS string\n\tF float64\n}\ntype MapFieldNestedStruct[K comparable] map[K]MapFieldValue\n\ntype Hello struct {\n\tMyStringField1       Field[*string]                `json:\"myStringField1\"`\n\tMyStringField2       Field[string]                 `json:\"myStringField2\"`\n\tMyArrayField         DoubleField[*string, string]  `json:\"myNewField\"`\n\tMyArrayDepthField    TrippleField[*string, string] `json:\"myNewArrayField\"`\n\tArrayField           ArrayField[string]            `json:\"arrayField\"`\n\tMapField             MapField[string, float64]     `json:\"mapField\"`\n\tOriginArrayField     []string                      `json:\"originArrayField\"`\n\tOriginMapField       map[string]float64            `json:\"originMapField\"`\n\tMapFieldNestedStruct MapFieldNestedStruct[string]  `json:\"mapFieldNestedStruct\"`\n}\n"
  },
  {
    "path": "testdata/generics_basic/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n)\n\ntype GenericBody[T any] struct {\n\tData T\n}\n\ntype GenericBodyMulti[T any, X any] struct {\n\tData T\n\tMeta X\n}\n\ntype GenericResponse[T any] struct {\n\tData T\n\n\tStatus string\n}\n\ntype GenericResponseMulti[T any, X any] struct {\n\tData T\n\tMeta X\n\n\tStatus string\n}\n\n// APIError\n// @Description API error\n// @Description with information about it\n// Other some summary\ntype APIError struct {\n\t// Error an Api error\n\tError string // Error this is Line comment\n\t// Error `number` tick comment\n\tErrorNo   int64\n\tErrorCtx  string    // Error `context` tick comment\n\tCreatedAt time.Time // Error time\n}\n"
  },
  {
    "path": "testdata/generics_function_scoped/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_function_scoped/types\"\n)\n\n// @Summary Generic Response\n// @Produce  json\n// @Success 200 {object} types.GenericResponse[api.GetGeneric.User]\n// @Success 201 {object} types.GenericResponse[api.GetGeneric.Post]\n// @Router / [get]\nfunc GetGeneric(w http.ResponseWriter, r *http.Request) {\n\ttype User struct {\n\t\tUsername int    `json:\"username\"`\n\t\tEmail    string `json:\"email\"`\n\t}\n\ttype Post struct {\n\t\tSlug  int    `json:\"slug\"`\n\t\tTitle string `json:\"title\"`\n\t}\n\n\t_ = types.GenericResponse[any]{}\n}\n\n// @Summary Generic Response With Custom Type Names\n// @Produce  json\n// @Success 200 {object} types.GenericResponse[api.GetGenericRenamed.User]\n// @Success 201 {object} types.GenericResponse[api.GetGenericRenamed.Post]\n// @Router /renamed [get]\nfunc GetGenericRenamed(w http.ResponseWriter, r *http.Request) {\n\ttype User struct {\n\t\tUsername int    `json:\"username\"`\n\t\tEmail    string `json:\"email\"`\n\t} // @Name RenamedUserData\n\ttype Post struct {\n\t\tSlug  int    `json:\"slug\"`\n\t\tTitle string `json:\"title\"`\n\t} // @Name RenamedPostData\n\n\t_ = types.GenericResponse[any]{}\n}\n\n// @Summary Multiple Generic Response\n// @Produce  json\n// @Success 200 {object} types.GenericMultiResponse[api.GetGenericMulti.MyStructA, api.GetGenericMulti.MyStructB]\n// @Success 201 {object} types.GenericMultiResponse[api.GetGenericMulti.MyStructB, api.GetGenericMulti.MyStructA]\n// @Router /multi [get]\nfunc GetGenericMulti(w http.ResponseWriter, r *http.Request) {\n\ttype MyStructA struct {\n\t\tSomeFieldA string `json:\"some_field_a\"`\n\t}\n\ttype MyStructB struct {\n\t\tSomeFieldB string `json:\"some_field_b\"`\n\t}\n\n\t_ = types.GenericMultiResponse[any, any]{}\n}\n\n// @Summary Multiple Generic Response With Custom Type Names\n// @Produce  json\n// @Success 200 {object} types.GenericMultiResponse[api.GetGenericMultiRenamed.MyStructA, api.GetGenericMultiRenamed.MyStructB]\n// @Success 201 {object} types.GenericMultiResponse[api.GetGenericMultiRenamed.MyStructB, api.GetGenericMultiRenamed.MyStructA]\n// @Router /multi-renamed [get]\nfunc GetGenericMultiRenamed(w http.ResponseWriter, r *http.Request) {\n\ttype MyStructA struct {\n\t\tSomeFieldA string `json:\"some_field_a\"`\n\t} // @Name NameForMyStructA\n\ttype MyStructB struct {\n\t\tSomeFieldB string `json:\"some_field_b\"`\n\t} // @Name NameForMyStructB\n\n\t_ = types.GenericMultiResponse[any, any]{}\n}\n"
  },
  {
    "path": "testdata/generics_function_scoped/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:8080\",\n    \"basePath\": \"/api\",\n    \"paths\": {\n        \"/\": {\n            \"get\": {\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Generic Response\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/types.GenericResponse-api_GetGeneric_User\"\n                        }\n                    },\n                    \"201\": {\n                        \"description\": \"Created\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/types.GenericResponse-api_GetGeneric_Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/multi\": {\n            \"get\": {\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Multiple Generic Response\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/types.GenericMultiResponse-api_GetGenericMulti_MyStructA-api_GetGenericMulti_MyStructB\"\n                        }\n                    },\n                    \"201\": {\n                        \"description\": \"Created\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/types.GenericMultiResponse-api_GetGenericMulti_MyStructB-api_GetGenericMulti_MyStructA\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/multi-renamed\": {\n            \"get\": {\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Multiple Generic Response With Custom Type Names\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/types.GenericMultiResponse-NameForMyStructA-NameForMyStructB\"\n                        }\n                    },\n                    \"201\": {\n                        \"description\": \"Created\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/types.GenericMultiResponse-NameForMyStructB-NameForMyStructA\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/renamed\": {\n            \"get\": {\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Generic Response With Custom Type Names\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/types.GenericResponse-RenamedUserData\"\n                        }\n                    },\n                    \"201\": {\n                        \"description\": \"Created\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/types.GenericResponse-RenamedPostData\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"NameForMyStructA\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"some_field_a\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"NameForMyStructB\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"some_field_b\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"RenamedPostData\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"slug\": {\n                    \"type\": \"integer\"\n                },\n                \"title\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"RenamedUserData\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"email\": {\n                    \"type\": \"string\"\n                },\n                \"username\": {\n                    \"type\": \"integer\"\n                }\n            }\n        },\n        \"api.GetGeneric.Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"slug\": {\n                    \"type\": \"integer\"\n                },\n                \"title\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.GetGeneric.User\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"email\": {\n                    \"type\": \"string\"\n                },\n                \"username\": {\n                    \"type\": \"integer\"\n                }\n            }\n        },\n        \"api.GetGenericMulti.MyStructA\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"some_field_a\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.GetGenericMulti.MyStructB\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"some_field_b\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.GenericMultiResponse-NameForMyStructA-NameForMyStructB\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data_t\": {\n                    \"$ref\": \"#/definitions/NameForMyStructA\"\n                },\n                \"data_x\": {\n                    \"$ref\": \"#/definitions/NameForMyStructB\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.GenericMultiResponse-NameForMyStructB-NameForMyStructA\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data_t\": {\n                    \"$ref\": \"#/definitions/NameForMyStructB\"\n                },\n                \"data_x\": {\n                    \"$ref\": \"#/definitions/NameForMyStructA\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.GenericMultiResponse-api_GetGenericMulti_MyStructA-api_GetGenericMulti_MyStructB\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data_t\": {\n                    \"$ref\": \"#/definitions/api.GetGenericMulti.MyStructA\"\n                },\n                \"data_x\": {\n                    \"$ref\": \"#/definitions/api.GetGenericMulti.MyStructB\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.GenericMultiResponse-api_GetGenericMulti_MyStructB-api_GetGenericMulti_MyStructA\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data_t\": {\n                    \"$ref\": \"#/definitions/api.GetGenericMulti.MyStructB\"\n                },\n                \"data_x\": {\n                    \"$ref\": \"#/definitions/api.GetGenericMulti.MyStructA\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.GenericResponse-RenamedPostData\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/RenamedPostData\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.GenericResponse-RenamedUserData\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/RenamedUserData\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.GenericResponse-api_GetGeneric_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/api.GetGeneric.Post\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.GenericResponse-api_GetGeneric_User\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/api.GetGeneric.User\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/generics_function_scoped/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_function_scoped/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server.\n// @host localhost:8080\n// @basePath /api\nfunc main() {\n\thttp.HandleFunc(\"/\", api.GetGeneric)\n\thttp.HandleFunc(\"/renamed\", api.GetGenericRenamed)\n\thttp.HandleFunc(\"/multi\", api.GetGenericMulti)\n\thttp.HandleFunc(\"/multi-renamed\", api.GetGenericMulti)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/generics_function_scoped/types/response.go",
    "content": "package types\n\ntype GenericResponse[T any] struct {\n\tStatus string `json:\"status\"`\n\tData   T      `json:\"data\"`\n}\n\ntype GenericMultiResponse[T any, X any] struct {\n\tStatus string `json:\"status\"`\n\tDataT  T      `json:\"data_t\"`\n\tDataX  X      `json:\"data_x\"`\n}\n"
  },
  {
    "path": "testdata/generics_multi_level_nesting/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n)\n\n// GetPosts\n// @Summary Test Generics with multi level nesting\n// @Description Test one of the edge cases found in generics\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} web.TestResponse\n// @Router /use-struct-and-generics-with-multi-level-nesting [get]\nfunc GetPosts(w http.ResponseWriter, r *http.Request) {\n\n}\n"
  },
  {
    "path": "testdata/generics_multi_level_nesting/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:4000\",\n    \"basePath\": \"/api\",\n    \"paths\": {\n        \"/use-struct-and-generics-with-multi-level-nesting\": {\n            \"get\": {\n                \"description\": \"Test one of the edge cases found in generics\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Test Generics with multi level nesting\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.TestResponse\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"web.DataPoint-float64\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"timestamp\": {\n                    \"type\": \"integer\"\n                },\n                \"value\": {\n                    \"type\": \"number\"\n                }\n            }\n        },\n        \"web.DataPoint-int64\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"timestamp\": {\n                    \"type\": \"integer\"\n                },\n                \"value\": {\n                    \"type\": \"integer\"\n                }\n            }\n        },\n        \"web.Entity-float64\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"line_with_fix_type\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.DataPoint-float64\"\n                    }\n                },\n                \"line_with_generic_type\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.DataPoint-float64\"\n                    }\n                },\n                \"multiple_lines\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.NamedLineData-float64\"\n                    }\n                }\n            }\n        },\n        \"web.Entity-int64\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"line_with_fix_type\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.DataPoint-float64\"\n                    }\n                },\n                \"line_with_generic_type\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.DataPoint-int64\"\n                    }\n                },\n                \"multiple_lines\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.NamedLineData-int64\"\n                    }\n                }\n            }\n        },\n        \"web.NamedLineData-float64\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.DataPoint-float64\"\n                    }\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.NamedLineData-int64\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.DataPoint-int64\"\n                    }\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.TestResponse\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"field_1\": {\n                    \"$ref\": \"#/definitions/web.Entity-int64\"\n                },\n                \"field_2\": {\n                    \"$ref\": \"#/definitions/web.Entity-float64\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/generics_multi_level_nesting/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_nested_my_version/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @host localhost:4000\n// @basePath /api\nfunc main() {\n\thttp.HandleFunc(\"/posts/\", api.GetPosts)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/generics_multi_level_nesting/web/handler.go",
    "content": "package web\n\nimport (\n\t\"encoding/json\"\n)\n\ntype TestResponse struct {\n\tField1 Entity[int64]   `json:\"field_1\"`\n\tField2 Entity[float64] `json:\"field_2\"`\n}\n\ntype Entity[T int64 | float64] struct {\n\tLineWithFixType     EmptyArray[DataPoint[float64]] `json:\"line_with_fix_type\"`\n\tLineWithGenericType EmptyArray[DataPoint[T]]       `json:\"line_with_generic_type\"`\n\tMultipleLines       MultipleLines[T]               `json:\"multiple_lines\"`\n}\n\ntype DataPoint[T int64 | float64] struct {\n\tValue     T     `json:\"value\"`\n\tTimestamp int64 `json:\"timestamp\"`\n}\n\n// EmptyArray will show [] instead of nil.\ntype EmptyArray[T any] []T\n\nfunc (arr EmptyArray[T]) MarshalJSON() ([]byte, error) {\n\tif arr != nil {\n\t\treturn json.Marshal([]T(arr))\n\t}\n\n\treturn json.Marshal(make([]T, 0))\n}\n\ntype MultipleLines[T int64 | float64] []NamedLineData[T]\n\ntype NamedLineData[T int64 | float64] struct {\n\tName string                   `json:\"name\"`\n\tData EmptyArray[DataPoint[T]] `json:\"data\"`\n}\n"
  },
  {
    "path": "testdata/generics_names/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_names/types\"\n\t\"github.com/swaggo/swag/testdata/generics_names/web\"\n)\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @Accept  json\n// @Produce  json\n// @Param   data        body   web.GenericBody[types.Post]    true  \"Some ID\"\n// @Success 200 {object} web.GenericResponse[types.Post]\n// @Success 222 {object} web.GenericResponseMulti[types.Post, types.Post]\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /posts/ [post]\nfunc GetPost(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\t_ = web.GenericResponse[types.Post]{}\n}\n\n// @Summary Add new pets to the store\n// @Description get string by ID\n// @Accept  json\n// @Produce  json\n// @Param   data\tbody\tweb.GenericBodyMulti[types.Post, types.Post]\ttrue\t\"Some ID\"\n// @Success 200 {object} web.GenericResponse[types.Post]\n// @Success 222 {object} web.GenericResponseMulti[types.Post, types.Post]\n// @Router /posts-multi/ [post]\nfunc GetPostMulti(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\t_ = web.GenericResponse[types.Post]{}\n}\n\n// @Summary Add new pets to the store\n// @Description get string by ID\n// @Accept  json\n// @Produce  json\n// @Param   data\tbody\tweb.GenericBodyMulti[[]types.Post, [][]types.Post]\ttrue\t\"Some ID\"\n// @Success 200 {object} web.GenericResponse[[]types.Post]\n// @Success 222 {object} web.GenericResponseMulti[[]types.Post, [][]types.Post]\n// @Router /posts-multis/ [post]\nfunc GetPostArray(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\t_ = web.GenericResponse[types.Post]{}\n}\n"
  },
  {
    "path": "testdata/generics_names/api/api_alias_pkg.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\tmytypes \"github.com/swaggo/swag/testdata/generics_names/types\"\n\tmyweb \"github.com/swaggo/swag/testdata/generics_names/web\"\n)\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} myweb.AliasPkgGenericResponse[mytypes.Post]\n// @Router /posts/aliaspkg [post]\nfunc GetPostFromAliasPkg(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\t_ = myweb.AliasPkgGenericResponse[mytypes.Post]{}\n}\n"
  },
  {
    "path": "testdata/generics_names/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:4000\",\n    \"basePath\": \"/api\",\n    \"paths\": {\n        \"/posts-multi/\": {\n            \"post\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add new pets to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/MultiBody-Post-Post\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/Response-Post\"\n                        }\n                    },\n                    \"222\": {\n                        \"description\": \"\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/MultiResponse-Post-Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/posts-multis/\": {\n            \"post\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add new pets to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/MultiBody-array_Post-array_array_Post\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/Response-array_Post\"\n                        }\n                    },\n                    \"222\": {\n                        \"description\": \"\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/MultiResponse-array_Post-array_array_Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/posts/\": {\n            \"post\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add a new pet to the store\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/Body-Post\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/Response-Post\"\n                        }\n                    },\n                    \"222\": {\n                        \"description\": \"\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/MultiResponse-Post-Post\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/posts/aliaspkg\": {\n            \"post\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add a new pet to the store\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.AliasPkgGenericResponse-Post\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"Body-Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/Post\"\n                }\n            }\n        },\n        \"MultiBody-Post-Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/Post\"\n                },\n                \"meta\": {\n                    \"$ref\": \"#/definitions/Post\"\n                }\n            }\n        },\n        \"MultiBody-array_Post-array_array_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/Post\"\n                    }\n                },\n                \"meta\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"MultiResponse-Post-Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/Post\"\n                },\n                \"meta\": {\n                    \"$ref\": \"#/definitions/Post\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"MultiResponse-array_Post-array_array_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/Post\"\n                    }\n                },\n                \"meta\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/Post\"\n                        }\n                    }\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"@uri\": {\n                    \"type\": \"string\"\n                },\n                \"data\": {\n                    \"description\": \"Post data\",\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"name\": {\n                            \"description\": \"Post tag\",\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"string\"\n                            }\n                        }\n                    }\n                },\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\",\n                    \"example\": 1\n                },\n                \"name\": {\n                    \"description\": \"Post name\",\n                    \"type\": \"string\",\n                    \"example\": \"poti\"\n                }\n            }\n        },\n        \"Response-Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/Post\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"Response-array_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/Post\"\n                    }\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.APIError\": {\n            \"description\": \"API error with information about it\",\n            \"type\": \"object\",\n            \"properties\": {\n                \"createdAt\": {\n                    \"description\": \"Error time\",\n                    \"type\": \"string\"\n                },\n                \"error\": {\n                    \"description\": \"Error an Api error\",\n                    \"type\": \"string\"\n                },\n                \"errorCtx\": {\n                    \"description\": \"Error `context` tick comment\",\n                    \"type\": \"string\"\n                },\n                \"errorNo\": {\n                    \"description\": \"Error `number` tick comment\",\n                    \"type\": \"integer\",\n                    \"format\": \"int64\"\n                }\n            }\n        },\n        \"web.AliasPkgGenericResponse-Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"$ref\": \"#/definitions/Post\"\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/generics_names/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_names/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @host localhost:4000\n// @basePath /api\nfunc main() {\n\thttp.HandleFunc(\"/posts/\", api.GetPost)\n\thttp.HandleFunc(\"/posts-multi/\", api.GetPostMulti)\n\thttp.HandleFunc(\"/posts-multis/\", api.GetPostArray)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/generics_names/types/post.go",
    "content": "package types\n\ntype APIBase struct {\n\tAPIUrl string `json:\"@uri,omitempty\"`\n\tID     int    `json:\"id\" example:\"1\" format:\"int64\"`\n}\n\ntype Post struct {\n\tAPIBase\n\t// Post name\n\tName string `json:\"name\" example:\"poti\"`\n\t// Post data\n\tData struct {\n\t\t// Post tag\n\t\tTag []string `json:\"name\"`\n\t} `json:\"data\"`\n} // @name Post\n"
  },
  {
    "path": "testdata/generics_names/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n)\n\ntype GenericBody[T any] struct {\n\tData T\n} // @name Body\n\ntype GenericBodyMulti[T any, X any] struct {\n\tData T\n\tMeta X\n} // @name MultiBody\n\ntype GenericResponse[T any] struct {\n\tData T\n\n\tStatus string\n} // @name Response\n\ntype GenericResponseMulti[T any, X any] struct {\n\tData T\n\tMeta X\n\n\tStatus string\n} // @name MultiResponse\n\n// APIError\n// @Description API error\n// @Description with information about it\n// Other some summary\ntype APIError struct {\n\t// Error an Api error\n\tError string // Error this is Line comment\n\t// Error `number` tick comment\n\tErrorNo   int64\n\tErrorCtx  string    // Error `context` tick comment\n\tCreatedAt time.Time // Error time\n}\n\ntype AliasPkgGenericResponse[T any] struct {\n\tData T\n\n\tStatus string\n}\n"
  },
  {
    "path": "testdata/generics_nested/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_nested/types\"\n\t\"github.com/swaggo/swag/testdata/generics_nested/web\"\n)\n\n// @Summary List Posts\n// @Description Get All of the Posts\n// @Accept  json\n// @Produce  json\n// @Param   data\tbody\tweb.GenericNestedBody[web.GenericInnerType[types.Post]]\ttrue\t\"Some ID\"\n// @Success 200 {object} web.GenericNestedResponse[types.Post]\n// @Success 201 {object} web.GenericNestedResponse[web.GenericInnerType[types.Post]]\n// @Success 202 {object} web.GenericNestedResponseMulti[types.Post, web.GenericInnerMultiType[types.Post, types.Post]]\n// @Success 203 {object} web.GenericNestedResponseMulti[types.Post, web.GenericInnerMultiType[types.Post, web.GenericInnerType[types.Post]]]\n// @Success 222 {object} web.GenericNestedResponseMulti[web.GenericInnerType[types.Post], types.Post]\n// @Router /posts [get]\nfunc GetPosts(w http.ResponseWriter, r *http.Request) {\n\t_ = web.GenericNestedResponse[types.Post]{}\n}\n\n// @Summary List Posts\n// @Description Get All of the Posts\n// @Accept  json\n// @Produce  json\n// @Param   data\tbody\tweb.GenericNestedBody[web.GenericInnerType[[]types.Post]]\ttrue\t\"Some ID\"\n// @Success 200 {object} web.GenericNestedResponse[[]types.Post]\n// @Success 201 {object} web.GenericNestedResponse[[]web.GenericInnerType[types.Post]]\n// @Success 202 {object} web.GenericNestedResponse[[]web.GenericInnerType[[]types.Post]]\n// @Success 203 {object} web.GenericNestedResponseMulti[[]types.Post, web.GenericInnerMultiType[[]types.Post, types.Post]]\n// @Success 204 {object} web.GenericNestedResponseMulti[[]types.Post, []web.GenericInnerMultiType[[]types.Post, types.Post]]\n// @Success 205 {object} web.GenericNestedResponseMulti[types.Post, web.GenericInnerMultiType[types.Post, []web.GenericInnerType[[][]types.Post]]]\n// @Success 222 {object} web.GenericNestedResponseMulti[web.GenericInnerType[[]types.Post], []types.Post]\n// @Router /posts-multis/ [get]\nfunc GetPostArray(w http.ResponseWriter, r *http.Request) {\n\t_ = web.GenericNestedResponse[types.Post]{}\n}\n\n// @Summary List Posts\n// @Description Get All of the Posts\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} web.GenericNodeThree[string]\n// @Router /posts-self-nested-struct/ [get]\nfunc GetPostSelfNestStruct(w http.ResponseWriter, r *http.Request) {\n\n}\n"
  },
  {
    "path": "testdata/generics_nested/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:4000\",\n    \"basePath\": \"/api\",\n    \"paths\": {\n        \"/posts\": {\n            \"get\": {\n                \"description\": \"Get All of the Posts\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"List Posts\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedBody-web_GenericInnerType-types_Post\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponse-types_Post\"\n                        }\n                    },\n                    \"201\": {\n                        \"description\": \"Created\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponse-web_GenericInnerType-types_Post\"\n                        }\n                    },\n                    \"202\": {\n                        \"description\": \"Accepted\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponseMulti-types_Post-web_GenericInnerMultiType-types_Post-types_Post\"\n                        }\n                    },\n                    \"203\": {\n                        \"description\": \"Non-Authoritative Information\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponseMulti-types_Post-web_GenericInnerMultiType-types_Post-web_GenericInnerType-types_Post\"\n                        }\n                    },\n                    \"222\": {\n                        \"description\": \"\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponseMulti-web_GenericInnerType-types_Post-types_Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/posts-multis/\": {\n            \"get\": {\n                \"description\": \"Get All of the Posts\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"List Posts\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedBody-web_GenericInnerType-array_types_Post\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponse-array_types_Post\"\n                        }\n                    },\n                    \"201\": {\n                        \"description\": \"Created\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponse-array_web_GenericInnerType-types_Post\"\n                        }\n                    },\n                    \"202\": {\n                        \"description\": \"Accepted\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponse-array_web_GenericInnerType-array_types_Post\"\n                        }\n                    },\n                    \"203\": {\n                        \"description\": \"Non-Authoritative Information\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponseMulti-array_types_Post-web_GenericInnerMultiType-array_types_Post-types_Post\"\n                        }\n                    },\n                    \"204\": {\n                        \"description\": \"No Content\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponseMulti-array_types_Post-array_web_GenericInnerMultiType-array_types_Post-types_Post\"\n                        }\n                    },\n                    \"205\": {\n                        \"description\": \"Reset Content\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponseMulti-types_Post-web_GenericInnerMultiType-types_Post-array_web_GenericInnerType-array_array_types_Post\"\n                        }\n                    },\n                    \"222\": {\n                        \"description\": \"\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNestedResponseMulti-web_GenericInnerType-array_types_Post-array_types_Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/posts-self-nested-struct/\": {\n            \"get\": {\n                \"description\": \"Get All of the Posts\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"List Posts\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.GenericNodeThree-string\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"types.Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"@uri\": {\n                    \"type\": \"string\"\n                },\n                \"data\": {\n                    \"description\": \"Post data\",\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"name\": {\n                            \"description\": \"Post tag\",\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"string\"\n                            }\n                        }\n                    }\n                },\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\",\n                    \"example\": 1\n                },\n                \"name\": {\n                    \"description\": \"Post name\",\n                    \"type\": \"string\",\n                    \"example\": \"poti\"\n                }\n            }\n        },\n        \"web.GenericInnerMultiType-array_types_Post-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                }\n            }\n        },\n        \"web.GenericInnerMultiType-types_Post-array_web_GenericInnerType-array_array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    ]\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/web.GenericInnerType-array_array_types_Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"web.GenericInnerMultiType-types_Post-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    ]\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                }\n            }\n        },\n        \"web.GenericInnerMultiType-types_Post-web_GenericInnerType-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    ]\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.GenericInnerType-types_Post\"\n                    }\n                }\n            }\n        },\n        \"web.GenericInnerType-array_array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    }\n                }\n            }\n        },\n        \"web.GenericInnerType-array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                }\n            }\n        },\n        \"web.GenericInnerType-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    ]\n                }\n            }\n        },\n        \"web.GenericNestedBody-web_GenericInnerType-array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/web.GenericInnerType-array_types_Post\"\n                        }\n                    ]\n                },\n                \"status\": {\n                    \"description\": \"Status of some other stuff\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedBody-web_GenericInnerType-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/web.GenericInnerType-types_Post\"\n                        }\n                    ]\n                },\n                \"status\": {\n                    \"description\": \"Status of some other stuff\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponse-array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of some other stuff\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponse-array_web_GenericInnerType-array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/web.GenericInnerType-array_types_Post\"\n                        }\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of some other stuff\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponse-array_web_GenericInnerType-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/web.GenericInnerType-types_Post\"\n                        }\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of some other stuff\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponse-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of some other stuff\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponse-web_GenericInnerType-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"description\": \"Items from the list response\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.GenericInnerType-types_Post\"\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of some other stuff\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponseMulti-array_types_Post-array_web_GenericInnerMultiType-array_types_Post-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/web.GenericInnerMultiType-array_types_Post-types_Post\"\n                        }\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of the things\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponseMulti-array_types_Post-web_GenericInnerMultiType-array_types_Post-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.GenericInnerMultiType-array_types_Post-types_Post\"\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of the things\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponseMulti-types_Post-web_GenericInnerMultiType-types_Post-array_web_GenericInnerType-array_array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    ]\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.GenericInnerMultiType-types_Post-array_web_GenericInnerType-array_array_types_Post\"\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of the things\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponseMulti-types_Post-web_GenericInnerMultiType-types_Post-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    ]\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.GenericInnerMultiType-types_Post-types_Post\"\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of the things\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponseMulti-types_Post-web_GenericInnerMultiType-types_Post-web_GenericInnerType-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    ]\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.GenericInnerMultiType-types_Post-web_GenericInnerType-types_Post\"\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of the things\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponseMulti-web_GenericInnerType-array_types_Post-array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/web.GenericInnerType-array_types_Post\"\n                        }\n                    ]\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of the things\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNestedResponseMulti-web_GenericInnerType-types_Post-types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"itemOne\": {\n                    \"description\": \"ItemsOne is the first thing\",\n                    \"allOf\": [\n                        {\n                            \"$ref\": \"#/definitions/web.GenericInnerType-types_Post\"\n                        }\n                    ]\n                },\n                \"itemsTwo\": {\n                    \"description\": \"ItemsTwo is the second thing\",\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"status\": {\n                    \"description\": \"Status of the things\",\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.GenericNodeThree-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"current\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    }\n                },\n                \"next\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.GenericNodeThree-string\"\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/generics_nested/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_nested/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @host localhost:4000\n// @basePath /api\nfunc main() {\n\thttp.HandleFunc(\"/posts/\", api.GetPosts)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/generics_nested/types/post.go",
    "content": "package types\n\ntype APIBase struct {\n\tAPIUrl string `json:\"@uri,omitempty\"`\n\tID     int    `json:\"id\" example:\"1\" format:\"int64\"`\n}\n\ntype Post struct {\n\tAPIBase\n\t// Post name\n\tName string `json:\"name\" example:\"poti\"`\n\t// Post data\n\tData struct {\n\t\t// Post tag\n\t\tTag []string `json:\"name\"`\n\t} `json:\"data\"`\n}\n"
  },
  {
    "path": "testdata/generics_nested/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n)\n\n// GenericNestedBody[T]\n// @Description Some Generic Body\ntype GenericNestedBody[T any] struct {\n\t// Items from the list response\n\tItems T\n\t// Status of some other stuff\n\tStatus string\n}\n\n// GenericInnerType[T]\n// @Description Some Generic Body\ntype GenericInnerType[T any] struct {\n\t// Items from the list response\n\tItems T\n}\n\n// GenericInnerMultiType[T, X]\n// @Description Some Generic Body\ntype GenericInnerMultiType[T any, X any] struct {\n\t// ItemsOne is the first thing\n\tItemOne T\n\t// ItemsTwo is the second thing\n\tItemsTwo []X\n}\n\n// GenericNestedResponse[T]\n// @Description Some Generic List Response\ntype GenericNestedResponse[T any] struct {\n\t// Items from the list response\n\tItems []T\n\t// Status of some other stuff\n\tStatus string\n}\n\n// GenericNestedResponseMulti[T, X]\n// @Description this contains a few things\ntype GenericNestedResponseMulti[T any, X any] struct {\n\t// ItemsOne is the first thing\n\tItemOne T\n\t// ItemsTwo is the second thing\n\tItemsTwo []X\n\n\t// Status of the things\n\tStatus string\n}\n\n// APIError\n// @Description API error\n// @Description with information about it\n// Other some summary\ntype APIError struct {\n\t// Error an Api error\n\tError string // Error this is Line comment\n\t// Error `number` tick comment\n\tErrorNo   int64\n\tErrorCtx  string    // Error `context` tick comment\n\tCreatedAt time.Time // Error time\n}\n\ntype GenericNodeThree[T any] struct {\n\tCurrentData []T                    `json:\"current\"`\n\tNext        []*GenericNodeThree[T] `json:\"next\"`\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/external/external1/external.go",
    "content": "package external1\n\ntype Customer struct {\n\tName string\n\tAge  int\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/external/external2/external.go",
    "content": "package external2\n\ntype Customer struct {\n\tName string\n\tAge  int\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/external/external3/external.go",
    "content": "package external3\n\ntype Customer struct {\n\tName string\n\tAge  int\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/external/external4/external.go",
    "content": "package external4\n\ntype Customer struct {\n\tName string\n\tAge  int\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/api/api1.go",
    "content": "package api\n\nimport (\n\tmyv1 \"github.com/swaggo/swag/testdata/generics_package_alias/internal/path1/v1\"\n)\n\n// @Summary Create movie\n// @Description Create a new movie production\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} myv1.ListResult[myv1.ProductDto] \"\"\n// @Router /api01 [post]\nfunc CreateMovie01() {\n\t_ = myv1.ListResult[myv1.ProductDto]{}\n}\n\n// @Summary Create movie\n// @Description Create a new movie production\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} myv1.RenamedListResult[myv1.RenamedProductDto] \"\"\n// @Router /api02 [post]\nfunc CreateMovie02() {\n\t_ = myv1.ListResult[myv1.ProductDto]{}\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/api/api2.go",
    "content": "package api\n\nimport (\n\tmyv1 \"github.com/swaggo/swag/testdata/generics_package_alias/internal/path1/v1\"\n\tmyv2 \"github.com/swaggo/swag/testdata/generics_package_alias/internal/path2/v1\"\n)\n\n// @Summary Create movie\n// @Description Create a new movie production\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} myv2.ListResult[myv2.ProductDto] \"\"\n// @Router /api03 [post]\nfunc CreateMovie03() {\n\t_ = myv2.ListResult[myv2.ProductDto]{}\n}\n\n// @Summary Create movie\n// @Description Create a new movie production\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} myv2.RenamedListResult[myv2.RenamedProductDto] \"\"\n// @Router /api04 [post]\nfunc CreateMovie04() {\n\t_ = myv2.ListResult[myv2.ProductDto]{}\n}\n\n// @Summary Create movie\n// @Description Create a new movie production\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} myv1.ListResult[myv2.ProductDto] \"\"\n// @Router /api05 [post]\nfunc CreateMovie05() {\n\t_ = myv1.ListResult[myv2.ProductDto]{}\n}\n\n// @Summary Create movie\n// @Description Create a new movie production\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} myv1.RenamedListResult[myv2.RenamedProductDto] \"\"\n// @Router /api06 [post]\nfunc CreateMovie06() {\n\t_ = myv1.ListResult[myv2.ProductDto]{}\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/api/api3.go",
    "content": "package api\n\nimport (\n\t_ \"github.com/swaggo/swag/testdata/generics_package_alias/internal/path1/v1\"\n\t. \"github.com/swaggo/swag/testdata/generics_package_alias/internal/path2/v1\"\n)\n\n// @Summary Create movie\n// @Description models imported from an unnamed package\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} v1.ListResult[v1.ProductDto] \"\"\n// @Router /api07 [post]\nfunc CreateMovie07() {\n\tvar _ ProductDto\n}\n\n// @Summary Create movie\n// @Description models imported from an unnamed package\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} ListResult[ProductDto] \"\"\n// @Router /api08 [post]\nfunc CreateMovie08() {\n\tvar _ ProductDto\n}\n\n// @Summary Create movie\n// @Description models imported from an unnamed package\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} ListResult[v1.ProductDto] \"\"\n// @Router /api09 [post]\nfunc CreateMovie09() {\n\tvar _ ProductDto\n}\n\n// @Summary Create movie\n// @Description models imported from an unnamed package\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} v1.ListResult[ProductDto] \"\"\n// @Router /api10 [post]\nfunc CreateMovie10() {\n\tvar _ ProductDto\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/api/api4.go",
    "content": "package api\n\nimport (\n\t\"github.com/swaggo/swag/testdata/generics_package_alias/external/external1\"\n\t_ \"github.com/swaggo/swag/testdata/generics_package_alias/internal/path1/v1\"\n)\n\n// @Summary Create movie\n// @Description models imported from an external package\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} v1.ListResult[external1.Customer] \"\"\n// @Router /api11 [post]\nfunc CreateMovie11() {\n\tvar _ external1.Customer\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/api/api5.go",
    "content": "package api\n\nimport (\n\tmyexternal \"github.com/swaggo/swag/testdata/generics_package_alias/external/external2\"\n\t_ \"github.com/swaggo/swag/testdata/generics_package_alias/internal/path1/v1\"\n)\n\n// @Summary Create movie\n// @Description models imported from a named external package\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} v1.ListResult[myexternal.Customer] \"\"\n// @Router /api12 [post]\nfunc CreateMovie12() {\n\tvar _ myexternal.Customer\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/api/api6.go",
    "content": "package api\n\nimport (\n\t. \"github.com/swaggo/swag/testdata/generics_package_alias/external/external3\"\n\t_ \"github.com/swaggo/swag/testdata/generics_package_alias/internal/path1/v1\"\n)\n\n// @Summary Create movie\n// @Description models from an external package imported by mode dot\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} v1.ListResult[Customer] \"\"\n// @Router /api13 [post]\nfunc CreateMovie13() {\n\tvar _ Customer\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/api/api7.go",
    "content": "package api\n\nimport (\n\t_ \"github.com/swaggo/swag/testdata/generics_package_alias/external/external4\"\n\t_ \"github.com/swaggo/swag/testdata/generics_package_alias/internal/path1/v1\"\n)\n\n// @Summary Create movie\n// @Description models imported from an unnamed external package\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} v1.ListResult[external4.Customer] \"\"\n// @Router /api14 [post]\nfunc CreateMovie14() {\n\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/api/api8.go",
    "content": "package api\n\nimport (\n\t_ \"github.com/swaggo/swag/testdata/generics_package_alias/internal/path1/v1\"\n\t_ \"github.com/swaggo/swag/testdata/generics_package_alias/internal/path2/v1\"\n)\n\n// @Summary Create movie\n// @Description model from a package whose name conflicts with other packages\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} v1.UniqueProduct \"\"\n// @Router /api15 [post]\nfunc CreateMovie15() {\n\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"contact\": {}\n    },\n    \"paths\": {\n        \"/api01\": {\n            \"post\": {\n                \"description\": \"Create a new movie production\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1_ProductDto\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api02\": {\n            \"post\": {\n                \"description\": \"Create a new movie production\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/ListResultV1-ProductDtoV1\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api03\": {\n            \"post\": {\n                \"description\": \"Create a new movie production\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1.ListResult-github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1_ProductDto\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api04\": {\n            \"post\": {\n                \"description\": \"Create a new movie production\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/ListResultV2-ProductDtoV2\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api05\": {\n            \"post\": {\n                \"description\": \"Create a new movie production\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1_ProductDto\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api06\": {\n            \"post\": {\n                \"description\": \"Create a new movie production\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/ListResultV1-ProductDtoV2\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api07\": {\n            \"post\": {\n                \"description\": \"models imported from an unnamed package\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1_ProductDto\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api08\": {\n            \"post\": {\n                \"description\": \"models imported from an unnamed package\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1.ListResult-github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1_ProductDto\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api09\": {\n            \"post\": {\n                \"description\": \"models imported from an unnamed package\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1.ListResult-github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1_ProductDto\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api10\": {\n            \"post\": {\n                \"description\": \"models imported from an unnamed package\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1_ProductDto\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api11\": {\n            \"post\": {\n                \"description\": \"models imported from an external package\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-external1_Customer\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api12\": {\n            \"post\": {\n                \"description\": \"models imported from a named external package\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-external2_Customer\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api13\": {\n            \"post\": {\n                \"description\": \"models from an external package imported by mode dot\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-external3_Customer\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api14\": {\n            \"post\": {\n                \"description\": \"models imported from an unnamed external package\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-external4_Customer\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/api15\": {\n            \"post\": {\n                \"description\": \"model from a package whose name conflicts with other packages\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/v1.UniqueProduct\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"ListResultV1-ProductDtoV1\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items11\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/ProductDtoV1\"\n                    }\n                }\n            }\n        },\n        \"ListResultV1-ProductDtoV2\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items11\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/ProductDtoV2\"\n                    }\n                }\n            }\n        },\n        \"ListResultV2-ProductDtoV2\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items22\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/ProductDtoV2\"\n                    }\n                }\n            }\n        },\n        \"ProductDtoV1\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name11\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"ProductDtoV2\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name22\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"external1.Customer\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"age\": {\n                    \"type\": \"integer\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"external2.Customer\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"age\": {\n                    \"type\": \"integer\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"external3.Customer\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"age\": {\n                    \"type\": \"integer\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"external4.Customer\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"age\": {\n                    \"type\": \"integer\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-external1_Customer\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items1\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/external1.Customer\"\n                    }\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-external2_Customer\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items1\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/external2.Customer\"\n                    }\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-external3_Customer\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items1\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/external3.Customer\"\n                    }\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-external4_Customer\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items1\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/external4.Customer\"\n                    }\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1_ProductDto\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items1\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ProductDto\"\n                    }\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ListResult-github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1_ProductDto\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items1\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1.ProductDto\"\n                    }\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ProductDto\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name1\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1.ListResult-github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1_ProductDto\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items2\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path1_v1.ProductDto\"\n                    }\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1.ListResult-github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1_ProductDto\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items2\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1.ProductDto\"\n                    }\n                }\n            }\n        },\n        \"github_com_swaggo_swag_testdata_generics_package_alias_internal_path2_v1.ProductDto\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name2\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"v1.UniqueProduct\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"unique_product_name\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/generics_package_alias/internal/main.go",
    "content": "package main\n\nfunc main() {\n\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/path1/v1/product.go",
    "content": "package v1\n\ntype ProductDto struct {\n\tName1 string `json:\"name1\"`\n}\n\ntype ListResult[T any] struct {\n\tItems1 []T `json:\"items1,omitempty\"`\n}\n\ntype RenamedProductDto struct {\n\tName11 string `json:\"name11\"`\n} // @name ProductDtoV1\n\ntype RenamedListResult[T any] struct {\n\tItems11 []T `json:\"items11,omitempty\"`\n} // @name ListResultV1\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/path2/v1/product.go",
    "content": "package v1\n\ntype ProductDto struct {\n\tName2 string `json:\"name2\"`\n}\n\ntype ListResult[T any] struct {\n\tItems2 []T `json:\"items2,omitempty\"`\n}\n\ntype RenamedProductDto struct {\n\tName22 string `json:\"name22\"`\n} // @name ProductDtoV2\n\ntype RenamedListResult[T any] struct {\n\tItems22 []T `json:\"items22,omitempty\"`\n} // @name ListResultV2\n\ntype UniqueProduct struct {\n\tUniqueProductName string `json:\"unique_product_name\"`\n}\n"
  },
  {
    "path": "testdata/generics_package_alias/internal/path3/v1/product.go",
    "content": "package v1\n\ntype ProductDto struct {\n\tName3 string `json:\"name3\"`\n}\n\ntype ListResult[T any] struct {\n\tItems3 []T `json:\"items3,omitempty\"`\n}\n\ntype RenamedProductDto struct {\n\tName33 string `json:\"name33\"`\n} // @name ProductDtoV3\n\ntype RenamedListResult[T any] struct {\n\tItems33 []T `json:\"items33,omitempty\"`\n} // @name ListResultV3\n"
  },
  {
    "path": "testdata/generics_property/api/api.go",
    "content": "package api\n\nimport (\n\t\"github.com/swaggo/swag/testdata/generics_property/types\"\n\t\"github.com/swaggo/swag/testdata/generics_property/web\"\n\t\"net/http\"\n)\n\ntype NestedResponse struct {\n\tweb.GenericResponse[[]string, *uint8]\n\tPost types.Field[[]types.Post]\n}\n\ntype Audience[T any] []T\n\ntype CreateMovie struct {\n\tName           string\n\tMainActor      types.Field[Person]\n\tSupportingCast types.Field[[]Person]\n\tDirectors      types.Field[*[]Person]\n\tCameraPeople   types.Field[[]*Person]\n\tProducer       types.Field[*Person]\n\tAudience       Audience[Person]\n\tAudienceNames  Audience[string]\n\tDetail1        types.Field[types.Field[Person]]\n\tDetail2        types.Field[types.Field[string]]\n}\n\ntype Person struct {\n\tName string\n}\n\n// @Summary List Posts\n// @Description Get All of the Posts\n// @Accept  json\n// @Produce  json\n// @Param   data query  web.PostPager true \"1\"\n// @Success 200 {object} web.PostResponse \"ok\"\n// @Success 201 {object} web.PostResponses \"ok\"\n// @Success 202 {object} web.StringResponse \"ok\"\n// @Success 203 {object} NestedResponse \"ok\"\n// @Router /posts [get]\nfunc GetPosts(w http.ResponseWriter, r *http.Request) {\n}\n\n// @Summary Create movie\n// @Description Create a new movie production\n// @Accept  json\n// @Produce  json\n// @Param   data body  CreateMovie true \"Movie Create-Payload\"\n// @Success 201 {object} CreateMovie \"ok\"\n// @Router /movie [post]\nfunc CreateMovieApi(w http.ResponseWriter, r *http.Request) {\n}\n"
  },
  {
    "path": "testdata/generics_property/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"localhost:4000\",\n    \"basePath\": \"/api\",\n    \"paths\": {\n        \"/movie\": {\n            \"post\": {\n                \"description\": \"Create a new movie production\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Create movie\",\n                \"parameters\": [\n                    {\n                        \"description\": \"Movie Create-Payload\",\n                        \"name\": \"data\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.CreateMovie\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"201\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.CreateMovie\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/posts\": {\n            \"get\": {\n                \"description\": \"Get All of the Posts\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"List Posts\",\n                \"parameters\": [\n                    {\n                        \"type\": \"string\",\n                        \"name\": \"next_id\",\n                        \"in\": \"query\"\n                    },\n                    {\n                        \"type\": \"integer\",\n                        \"name\": \"page\",\n                        \"in\": \"query\"\n                    },\n                    {\n                        \"type\": \"string\",\n                        \"name\": \"prev_id\",\n                        \"in\": \"query\"\n                    },\n                    {\n                        \"type\": \"integer\",\n                        \"name\": \"rows\",\n                        \"in\": \"query\"\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.PostResponse\"\n                        }\n                    },\n                    \"201\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.PostResponses\"\n                        }\n                    },\n                    \"202\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.StringResponse\"\n                        }\n                    },\n                    \"203\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.NestedResponse\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"api.CreateMovie\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"audience\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/api.Person\"\n                    }\n                },\n                \"audienceNames\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    }\n                },\n                \"cameraPeople\": {\n                    \"$ref\": \"#/definitions/types.Field-array_api_Person\"\n                },\n                \"detail1\": {\n                    \"$ref\": \"#/definitions/types.Field-types_Field-api_Person\"\n                },\n                \"detail2\": {\n                    \"$ref\": \"#/definitions/types.Field-types_Field-string\"\n                },\n                \"directors\": {\n                    \"$ref\": \"#/definitions/types.Field-array_api_Person\"\n                },\n                \"mainActor\": {\n                    \"$ref\": \"#/definitions/types.Field-api_Person\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                },\n                \"producer\": {\n                    \"$ref\": \"#/definitions/types.Field-api_Person\"\n                },\n                \"supportingCast\": {\n                    \"$ref\": \"#/definitions/types.Field-array_api_Person\"\n                }\n            }\n        },\n        \"api.NestedResponse\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    }\n                },\n                \"items2\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int32\"\n                },\n                \"post\": {\n                    \"$ref\": \"#/definitions/types.Field-array_types_Post\"\n                }\n            }\n        },\n        \"api.Person\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.Field-api_Person\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"value\": {\n                    \"$ref\": \"#/definitions/api.Person\"\n                },\n                \"value2\": {\n                    \"$ref\": \"#/definitions/api.Person\"\n                },\n                \"value3\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/api.Person\"\n                    }\n                },\n                \"value4\": {\n                    \"$ref\": \"#/definitions/types.SubField1-api_Person-string\"\n                }\n            }\n        },\n        \"types.Field-array_api_Person\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"value\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/api.Person\"\n                    }\n                },\n                \"value2\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/api.Person\"\n                    }\n                },\n                \"value3\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/api.Person\"\n                        }\n                    }\n                },\n                \"value4\": {\n                    \"$ref\": \"#/definitions/types.SubField1-array_api_Person-string\"\n                }\n            }\n        },\n        \"types.Field-array_types_Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"value\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"value2\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"value3\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/definitions/types.Post\"\n                        }\n                    }\n                },\n                \"value4\": {\n                    \"$ref\": \"#/definitions/types.SubField1-array_types_Post-string\"\n                }\n            }\n        },\n        \"types.Field-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"value\": {\n                    \"type\": \"string\"\n                },\n                \"value2\": {\n                    \"type\": \"string\"\n                },\n                \"value3\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    }\n                },\n                \"value4\": {\n                    \"$ref\": \"#/definitions/types.SubField1-string-string\"\n                }\n            }\n        },\n        \"types.Field-types_Field-api_Person\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"value\": {\n                    \"$ref\": \"#/definitions/types.Field-api_Person\"\n                },\n                \"value2\": {\n                    \"$ref\": \"#/definitions/types.Field-api_Person\"\n                },\n                \"value3\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Field-api_Person\"\n                    }\n                },\n                \"value4\": {\n                    \"$ref\": \"#/definitions/types.SubField1-types_Field-api_Person-string\"\n                }\n            }\n        },\n        \"types.Field-types_Field-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"value\": {\n                    \"$ref\": \"#/definitions/types.Field-string\"\n                },\n                \"value2\": {\n                    \"$ref\": \"#/definitions/types.Field-string\"\n                },\n                \"value3\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Field-string\"\n                    }\n                },\n                \"value4\": {\n                    \"$ref\": \"#/definitions/types.SubField1-types_Field-string-string\"\n                }\n            }\n        },\n        \"types.Post\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"@uri\": {\n                    \"$ref\": \"#/definitions/types.Field-string\"\n                },\n                \"data\": {\n                    \"description\": \"Post data\",\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"name\": {\n                            \"description\": \"Post tag\",\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"string\"\n                            }\n                        }\n                    }\n                },\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\",\n                    \"example\": 1\n                },\n                \"name\": {\n                    \"description\": \"Post name\",\n                    \"type\": \"string\",\n                    \"example\": \"poti\"\n                }\n            }\n        },\n        \"types.SubField1-api_Person-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"subValue1\": {\n                    \"$ref\": \"#/definitions/api.Person\"\n                },\n                \"subValue2\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.SubField1-array_api_Person-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"subValue1\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/api.Person\"\n                    }\n                },\n                \"subValue2\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.SubField1-array_types_Post-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"subValue1\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"subValue2\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.SubField1-string-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"subValue1\": {\n                    \"type\": \"string\"\n                },\n                \"subValue2\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.SubField1-types_Field-api_Person-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"subValue1\": {\n                    \"$ref\": \"#/definitions/types.Field-api_Person\"\n                },\n                \"subValue2\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"types.SubField1-types_Field-string-string\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"subValue1\": {\n                    \"$ref\": \"#/definitions/types.Field-string\"\n                },\n                \"subValue2\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.PostResponse\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"$ref\": \"#/definitions/types.Post\"\n                },\n                \"items2\": {\n                    \"$ref\": \"#/definitions/types.Post\"\n                }\n            }\n        },\n        \"web.PostResponses\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/types.Post\"\n                    }\n                },\n                \"items2\": {\n                    \"$ref\": \"#/definitions/types.Post\"\n                }\n            }\n        },\n        \"web.StringResponse\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"items\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    }\n                },\n                \"items2\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int32\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/generics_property/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/generics_property/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @host localhost:4000\n// @basePath /api\nfunc main() {\n\thttp.HandleFunc(\"/posts/\", api.GetPosts)\n\thttp.HandleFunc(\"/movie/\", api.CreateMovieApi)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/generics_property/types/post.go",
    "content": "package types\n\ntype SubField1[T any, T2 any] struct {\n\tSubValue1 T\n\tSubValue2 T2\n}\n\ntype Field[T any] struct {\n\tValue  T\n\tValue2 *T\n\tValue3 []T\n\tValue4 SubField1[T, string]\n}\n\ntype APIBase struct {\n\tAPIUrl Field[string] `json:\"@uri,omitempty\"`\n\tID     int           `json:\"id\" example:\"1\" format:\"int64\"`\n}\n\ntype Post struct {\n\tAPIBase\n\t// Post name\n\tName string `json:\"name\" example:\"poti\"`\n\t// Post data\n\tData struct {\n\t\t// Post tag\n\t\tTag []string `json:\"name\"`\n\t} `json:\"data\"`\n}\n"
  },
  {
    "path": "testdata/generics_property/web/handler.go",
    "content": "package web\n\nimport \"github.com/swaggo/swag/testdata/generics_property/types\"\n\ntype PostSelector func(selector func())\n\ntype Filter interface {\n\t~func(selector func())\n}\n\ntype query[T any, F Filter] interface {\n\tWhere(ps ...F) T\n}\n\ntype Pager[T query[T, F], F Filter] struct {\n\tRows   uint8   `json:\"rows\" form:\"rows\"`\n\tPage   int     `json:\"page\" form:\"page\"`\n\tNextID *string `json:\"next_id\" form:\"next_id\"`\n\tPrevID *string `json:\"prev_id\" form:\"prev_id\"`\n\tquery  T\n}\n\ntype String string\n\nfunc (String) Where(ps ...PostSelector) String {\n\treturn \"\"\n}\n\ntype PostPager struct {\n\tPager[String, PostSelector]\n\tSearch types.Field[string] `json:\"search\" form:\"search\"`\n}\n\ntype PostResponse struct {\n\tGenericResponse[types.Post, types.Post]\n}\n\ntype PostResponses struct {\n\tGenericResponse[[]types.Post, types.Post]\n}\n\ntype StringResponse struct {\n\tGenericResponse[[]string, *uint8]\n}\n\ntype GenericResponse[T any, T2 any] struct {\n\tItems  T\n\tItems2 T2\n}\n"
  },
  {
    "path": "testdata/global_override/api/api.go",
    "content": "package api\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/alias_type/types\"\n\t\"github.com/swaggo/swag/testdata/global_override/data\"\n)\n\n// @Summary Get application\n// @Description test get application\n// @ID get-application\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} data.ApplicationResponse\t\"ok\"\n// @Router /testapi/application [get]\nfunc GetApplication(w http.ResponseWriter, r *http.Request) {\n\tvar foo = data.ApplicationResponse{\n\t\tApplication: types.Application{\n\t\t\tName: \"name\",\n\t\t},\n\t\tApplicationArray: []types.Application{\n\t\t\t{Name: \"name\"},\n\t\t},\n\t}\n\tlog.Println(foo)\n\t//write your code\n}\n"
  },
  {
    "path": "testdata/global_override/data/applicationresponse.go",
    "content": "package data\n\nimport (\n\ttypesapplication \"github.com/swaggo/swag/testdata/global_override/types\"\n)\n\ntype ApplicationResponse struct {\n\ttypesapplication.TypeToEmbed\n\n\tApplication      typesapplication.Application   `json:\"application\"`\n\tApplication2     typesapplication.Application2  `json:\"application2\"`\n\tApplicationArray []typesapplication.Application `json:\"application_array\"`\n\tApplicationTime  typesapplication.DateOnly      `json:\"application_time\"`\n\tShouldSkip       typesapplication.ShouldSkip    `json:\"should_skip\"`\n}\n"
  },
  {
    "path": "testdata/global_override/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {\n        \"/testapi/application\": {\n            \"get\": {\n                \"description\": \"test get application\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Get application\",\n                \"operationId\": \"get-application\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/data.ApplicationResponse\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"data.ApplicationResponse\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"application\": {\n                    \"type\": \"string\"\n                },\n                \"application2\": {\n                    \"$ref\": \"#/definitions/othertypes.Application\"\n                },\n                \"application_array\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    }\n                },\n                \"application_time\": {\n                    \"type\": \"string\"\n                },\n                \"embedded\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"othertypes.Application\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"id\": {\n                    \"type\": \"integer\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/global_override/main.go",
    "content": "package global_override\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/global_override/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\nfunc main() {\n\thttp.HandleFunc(\"/testapi/application\", api.GetApplication)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/global_override/othertypes/application.go",
    "content": "package othertypes\n\ntype Application struct {\n\tID int\n}\n"
  },
  {
    "path": "testdata/global_override/types/application.go",
    "content": "package types\n\nimport \"time\"\n\ntype Application struct {\n\tName string\n}\n\ntype Application2 struct {\n\tName string\n}\n\ntype DateOnly time.Time\n\ntype TypeToEmbed struct {\n\tEmbedded string\n}\n\ntype ShouldSkip struct {\n\tName string\n}\n"
  },
  {
    "path": "testdata/global_security/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n)\n\n// @Summary default security\n// @Success 200\n// @Router /testapi/application [get]\nfunc GetApplication(w http.ResponseWriter, r *http.Request) {}\n\n// @Summary no security\n// @Security\n// @Success 200\n// @Router /testapi/nosec [get]\nfunc GetNoSec(w http.ResponseWriter, r *http.Request) {}\n\n// @Summary basic security\n// @Security BasicAuth\n// @Success 200\n// @Router /testapi/basic [get]\nfunc GetBasic(w http.ResponseWriter, r *http.Request) {}\n\n// @Summary oauth2 write\n// @Security OAuth2Application[write]\n// @Success 200\n// @Router /testapi/oauth/write [get]\nfunc GetOAuthWrite(w http.ResponseWriter, r *http.Request) {}\n\n// @Summary oauth2 admin\n// @Security OAuth2Application[admin]\n// @Success 200\n// @Router /testapi/oauth/admin [get]\nfunc GetOAuthAdmin(w http.ResponseWriter, r *http.Request) {}\n"
  },
  {
    "path": "testdata/global_security/expected.json",
    "content": "{\n  \"swagger\": \"2.0\",\n  \"info\": {\n    \"title\": \"Swagger Example API\",\n    \"contact\": {},\n    \"version\": \"1.0\"\n  },\n  \"paths\": {\n    \"/testapi/application\": {\n      \"get\": {\n        \"summary\": \"default security\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"OK\"\n          }\n        }\n      }\n    },\n    \"/testapi/basic\": {\n      \"get\": {\n        \"summary\": \"basic security\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"OK\"\n          }\n        },\n        \"security\": [\n          {\n            \"BasicAuth\": []\n          }\n        ]\n      }\n    },\n    \"/testapi/nosec\": {\n      \"get\": {\n        \"summary\": \"no security\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"OK\"\n          }\n        },\n        \"security\": []\n      }\n    },\n    \"/testapi/oauth/admin\": {\n      \"get\": {\n        \"summary\": \"oauth2 admin\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"OK\"\n          }\n        },\n        \"security\": [\n          {\n            \"OAuth2Application\": [\n              \"admin\"\n            ]\n          }\n        ]\n      }\n    },\n    \"/testapi/oauth/write\": {\n      \"get\": {\n        \"summary\": \"oauth2 write\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"OK\"\n          }\n        },\n        \"security\": [\n          {\n            \"OAuth2Application\": [\n              \"write\"\n            ]\n          }\n        ]\n      }\n    }\n  },\n  \"securityDefinitions\": {\n    \"APIKeyAuth\": {\n      \"type\": \"apiKey\",\n      \"name\": \"Authorization\",\n      \"in\": \"header\"\n    },\n    \"BasicAuth\": {\n      \"type\": \"basic\"\n    },\n    \"OAuth2Application\": {\n      \"type\": \"oauth2\",\n      \"flow\": \"application\",\n      \"tokenUrl\": \"https://example.com/oauth/token\",\n      \"scopes\": {\n        \"admin\": \"Grants read and write access to administrative information\",\n        \"write\": \"Grants write access\"\n      }\n    }\n  },\n  \"security\": [\n    {\n      \"APIKeyAuth\": [],\n      \"OAuth2Application\": []\n    }\n  ]\n}"
  },
  {
    "path": "testdata/global_security/main.go",
    "content": "package global_security\n\n// @title Swagger Example API\n// @version 1.0\n\n// @securityDefinitions.apikey APIKeyAuth\n// @in header\n// @name Authorization\n\n// @securityDefinitions.basic  BasicAuth\n\n// @securityDefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @security APIKeyAuth && OAuth2Application\nfunc main() {}\n"
  },
  {
    "path": "testdata/golist/api/api.go",
    "content": "package api\n\n/*\n#include \"foo.h\"\n*/\nimport \"C\"\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc PrintInt(i, j int) {\n\tres := C.add(C.int(i), C.int(j))\n\tfmt.Println(res)\n}\n\ntype Foo struct {\n\tID        int      `json:\"id\"`\n\tName      string   `json:\"name\"`\n\tPhotoUrls []string `json:\"photoUrls\"`\n\tStatus    string   `json:\"status\"`\n}\n\n// GetFoo example\n// @Summary Get foo\n// @Description get foo\n// @ID foo\n// @Accept  json\n// @Produce  json\n// @Param   some_id      query   int     true  \"Some ID\"\n// @Param\tsome_foo\t formData Foo true \"Foo\"\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /testapi/foo [get]\nfunc GetFoo(w http.ResponseWriter, r *http.Request) {\n\t// write your code\n}\n"
  },
  {
    "path": "testdata/golist/api/foo.c",
    "content": "int add(int a, int b) {\n    return a + b;\n}"
  },
  {
    "path": "testdata/golist/api/foo.h",
    "content": "int add(int, int);"
  },
  {
    "path": "testdata/golist/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/example/basic/api\"\n\tgoapi \"github.com/swaggo/swag/testdata/golist/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @securityDefinitions.apikey ApiKeyAuth\n// @in header\n// @name Authorization\n\n// @query.collection.format multi\n// @host petstore.swagger.io\n// @BasePath /v2\nfunc main() {\n\tgoapi.PrintInt(10, 5)\n\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\thttp.HandleFunc(\"/testapi/get-struct-array-by-string/\", api.GetStructArrayByString)\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.HandleFunc(\"/testapi/foo\", goapi.GetFoo)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/golist_disablemodule/api/api.go",
    "content": "package api\n\n/*\n#include \"foo.h\"\n*/\nimport \"C\"\nimport (\n\t\"fmt\"\n)\n\nfunc PrintInt(i, j int) {\n\tres := C.add(C.int(i), C.int(j))\n\tfmt.Println(res)\n}\n"
  },
  {
    "path": "testdata/golist_disablemodule/api/foo.c",
    "content": "int add(int a, int b) {\n    return a + b;\n}"
  },
  {
    "path": "testdata/golist_disablemodule/api/foo.h",
    "content": "int add(int, int);"
  },
  {
    "path": "testdata/golist_disablemodule/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/example/basic/api\"\n\tinternalapi \"github.com/swaggo/swag/testdata/golist_disablemodule/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @securityDefinitions.apikey ApiKeyAuth\n// @in header\n// @name Authorization\n\n// @host petstore.swagger.io\n// @BasePath /v2\nfunc main() {\n\tinternalapi.PrintInt(0, 1)\n\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\thttp.HandleFunc(\"/testapi/get-struct-array-by-string/\", api.GetStructArrayByString)\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/golist_invalid/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/example/basic/api\"\n\t\"github.com/swaggo/swag/testdata/invalid_external_pkg/invalid\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @securityDefinitions.apikey ApiKeyAuth\n// @in header\n// @name Authorization\n\n// @host petstore.swagger.io\n// @BasePath /v2\nfunc main() {\n\tinvalid.Foo()\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/invalid_external_pkg/invalid/normal.go",
    "content": "package invalid\n\nfunc Foo() {\n\n}\n"
  },
  {
    "path": "testdata/invalid_external_pkg/main.go",
    "content": "package main\n\nfunc main() {}\n"
  },
  {
    "path": "testdata/json_field_string/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n)\n\ntype MyStruct struct {\n\tID       int      `json:\"id\" example:\"1\" format:\"int64\"`\n\tName     string   `json:\"name\" example:\"poti\"`\n\tIntvar   int      `json:\"myint,string\"`                            // integer as string\n\tBoolvar  bool     `json:\",string\"`                                 // boolean as a string\n\tTrueBool bool     `json:\"truebool,string\" example:\"true\"`          // boolean as a string\n\tFloatvar float64  `json:\",string\"`                                 // float as a string\n\tUUIDs    []string `json:\"uuids\" type:\"array,string\" format:\"uuid\"` // string array with format\n}\n\n// @Summary Call DoSomething\n// @Description Does something\n// @Accept  json\n// @Produce  json\n// @Param body body MyStruct true \"My Struct\"\n// @Success 200 {object} MyStruct\n// @Failure 500\n// @Router /do-something [post]\nfunc DoSomething(w http.ResponseWriter, r *http.Request) {\n\tobjectFromJSON := new(MyStruct)\n\tif err := json.NewDecoder(r.Body).Decode(&objectFromJSON); err != nil {\n\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\tfmt.Print(err.Error())\n\t}\n\tjson.NewEncoder(w).Encode(ojbectFromJSON)\n}\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server.\n// @host localhost:4000\n// @basePath /\nfunc main() {\n\thttp.HandleFund(\"/do-something\", DoSomething)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/main.go",
    "content": "package main\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @description It has a lot of beautiful features.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\n// @schemes http https\n// @securityDefinitions.basic BasicAuth\n\n// @securityDefinitions.apikey ApiKeyAuth\n// @in header\n// @name Authorization\n// @description some description\n\n// @securitydefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.implicit OAuth2Implicit\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n// @x-google-audiences some_audience.google.com\n\n// @securitydefinitions.oauth2.password OAuth2Password\n// @tokenUrl https://example.com/oauth/token\n// @scope.read Grants read access\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.accessCode OAuth2AccessCode\n// @tokenUrl https://example.com/oauth/token\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.admin Grants read and write access to administrative information\n// @x-tokenname id_token\n\n// @externalDocs.description OpenAPI\n// @externalDocs.url https://swagger.io/resources/open-api\n\n// @x-google-endpoints [{\"name\":\"name.endpoints.environment.cloud.goog\",\"allowCors\":true}]\n// @x-google-marks \"marks values\"\n// @x-logo {\"url\":\"https://redocly.github.io/redoc/petstore-logo.png\", \"altText\": \"Petstore logo\", \"backgroundColor\": \"#FFFFFF\"}\n\nfunc main() {}\n"
  },
  {
    "path": "testdata/markdown.go",
    "content": "package main\n\n// @title Swagger Example API\n// @version 1.0\n// @description.markdown markdown.md\n// @termsOfService http://swagger.io/terms/\n\n// @tag.name users\n// @tag.description.markdown\n\nfunc main() {}\n"
  },
  {
    "path": "testdata/nested/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/nested2\"\n)\n\ntype Foo struct {\n\tField1      string `validate:\"required\"`\n\tOutsideData *nested2.Body\n\tInsideData  Bar      `validate:\"required\"`\n\tArrayField1 []string `validate:\"required\"`\n\tArrayField2 []Bar    `validate:\"required\"`\n}\n\ntype Bar struct {\n\tField string\n}\n\n// @Description get Foo\n// @ID get-foo\n// @Accept json\n// @Produce json\n// @Success 200 {object} api.Foo\n// @Router /testapi/get-foo [get]\nfunc GetFoo(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n\tvar _ = Foo{}\n}\n"
  },
  {
    "path": "testdata/nested/common/data.go",
    "content": "package common\n\ntype Data struct {\n\tValue string `json:\"message\"`\n}\n"
  },
  {
    "path": "testdata/nested/expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore.swagger.io\",\n    \"basePath\": \"/v2\",\n    \"paths\": {\n        \"/testapi/get-foo\": {\n            \"get\": {\n                \"description\": \"get Foo\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"operationId\": \"get-foo\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"OK\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/api.Foo\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"api.Bar\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"field\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"api.Foo\": {\n            \"type\": \"object\",\n            \"required\": [\n                \"arrayField1\",\n                \"arrayField2\",\n                \"field1\",\n                \"insideData\"\n            ],\n            \"properties\": {\n                \"arrayField1\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    }\n                },\n                \"arrayField2\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/api.Bar\"\n                    }\n                },\n                \"field1\": {\n                    \"type\": \"string\"\n                },\n                \"insideData\": {\n                    \"$ref\": \"#/definitions/api.Bar\"\n                },\n                \"outsideData\": {\n                    \"$ref\": \"#/definitions/nested2.Body\"\n                }\n            }\n        },\n        \"nested2.Body\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"value\": {\n                    \"type\": \"string\"\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testdata/nested/main.go",
    "content": "package composition\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/nested/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server\n// @termsOfService http://swagger.io/terms/\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\nfunc main() {\n\thttp.HandleFunc(\"/testapi/get-foo\", api.GetFoo)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/nested2/data.go",
    "content": "package nested2\n\ntype Body struct {\n\tValue string `json:\"value\"`\n}\n"
  },
  {
    "path": "testdata/nested2/inner/data.go",
    "content": "package inner\n"
  },
  {
    "path": "testdata/non_exported_json_fields/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n)\n\ntype MyStruct struct {\n\tID int `json:\"id\" example:\"1\" format:\"int64\"`\n\t// Post name\n\tName string `json:\"name\" example:\"poti\"`\n\t// Post data\n\tData struct {\n\t\t// Post tag\n\t\tTag []string `json:\"name\"`\n\t} `json:\"data\"`\n\t// not-exported variable, for internal use only, not marshaled\n\tinternal1 string\n\tinternal2 int\n\tinternal3 bool\n\tinternal4 struct {\n\t\tNestedInternal string\n\t}\n}\n\n// @Summary Call DoSomething\n// @Description Does something, but internal (non-exported) fields inside a struct won't be marshaled into JSON\n// @Accept  json\n// @Produce  json\n// @Success 200 {object} MyStruct\n// @Router /so-something [get]\nfunc DoSomething(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server.\n// @host localhost:4000\n// @basePath /api\nfunc main() {\n\thttp.HandleFunc(\"/do-something\", DoSomething)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/param_structs/structs.go",
    "content": "package structs\n\ntype FormModel struct {\n\tFoo string `form:\"f\" binding:\"required\" validate:\"max=10\"`\n\t// B is another field\n\tB bool\n}\n\ntype AuthHeader struct {\n\t// Token is the auth token\n\tToken string `header:\"X-Auth-Token\" binding:\"required\"`\n\t// AnotherHeader is another header\n\tAnotherHeader int `validate:\"gte=0,lte=10\"`\n}\n\ntype PathModel struct {\n\t// ID is the id\n\tIdentifier int    `uri:\"id\" binding:\"required\"`\n\tName       string `validate:\"max=10\"`\n}\n"
  },
  {
    "path": "testdata/pare_outside_dependencies/cmd/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/example/basic/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\nfunc main() {\n\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\thttp.HandleFunc(\"//testapi/get-struct-array-by-string/\", api.GetStructArrayByString)\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/parseExtension/parseExtension.go",
    "content": "package main\n\n// @Router /without-extension [get]\nfunc Fun() {}\n\n// @Router /with-another-extension [get]\n// @x-another-extension {\"address\": \"http://backend\"}\nfunc Fun2() {}\n\n// @Router /with-correct-extension [get]\n// @x-google-backend {\"address\": \"http://backend\"}\nfunc Fun3() {}\n\n// @Router /with-empty-comment-line [get]\nfunc FunEmptyCommentLine() {}\n"
  },
  {
    "path": "testdata/pet/main.go",
    "content": "package main\n\n// @title Swagger Petstore\n// @version 1.0\n// @description This is a sample server Petstore server.  You can find out more about     Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).      For this sample, you can use the api key 'special-key' to test the authorization     filters.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.email apiteam@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @basePath /v2\n// @schemes http https\nfunc main() {\n\n}\n"
  },
  {
    "path": "testdata/pet/web/handler.go",
    "content": "package web\n\ntype Pet struct {\n\tID       int `json:\"id\" example:\"1\"`\n\tCategory struct {\n\t\tID            int      `json:\"id\" example:\"1\"`\n\t\tName          string   `json:\"name\" example:\"category_name\"`\n\t\tPhotoUrls     []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\t\tSmallCategory struct {\n\t\t\tID        int      `json:\"id\" example:\"1\"`\n\t\t\tName      string   `json:\"name\" example:\"detail_category_name\"`\n\t\t\tPhotoUrls []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\t\t} `json:\"small_category\"`\n\t} `json:\"category\"`\n\tName      string   `json:\"name\" example:\"poti\"`\n\tPhotoUrls []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\tTags      []Tag    `json:\"tags\"`\n\tStatus    string   `json:\"status\"`\n\tPrice     float32  `json:\"price\" example:\"3.25\" multipleOf:\"0.01\"`\n\tIsAlive   bool     `json:\"is_alive\" example:\"true\"`\n}\n\ntype Tag struct {\n\tID   int    `json:\"id\"`\n\tName string `json:\"name\"`\n}\n"
  },
  {
    "path": "testdata/quotes/api/api.go",
    "content": "package api\n\n// RandomFunc dogoc\n// @Description.markdown api\n// @Success 200 {string} string\t\"ok\"\n// @Router /random [get]\nfunc RandomFunc() {}\n"
  },
  {
    "path": "testdata/quotes/api.md",
    "content": "# Title with \"quotes\"\n\nAs we want to verify that this markdown is formatted equally in both the general\nAPI description, in a tag description and in an endpoint description, the tag\ndefined in main.go is called api, and the markdown file name is specified\nmanually in the description comment in api/api.go.\n\n```json\n{\n\t\"with\": \"escaped \\\"quotes\\\"\",\n\t\"indentedWith\": \"tabs\",\n\t\"foo\": \"bar\",\n\t\"baz\": null\n}\n```\n\nSome more text.\n"
  },
  {
    "path": "testdata/quotes/expected.json",
    "content": "{\n    \"schemes\": [],\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"# Title with \\\"quotes\\\"\\n\\nAs we want to verify that this markdown is formatted equally in both the general\\nAPI description, in a tag description and in an endpoint description, the tag\\ndefined in main.go is called api, and the markdown file name is specified\\nmanually in the description comment in api/api.go.\\n\\n```json\\n{\\n\\t\\\"with\\\": \\\"escaped \\\\\\\"quotes\\\\\\\"\\\",\\n\\t\\\"indentedWith\\\": \\\"tabs\\\",\\n\\t\\\"foo\\\": \\\"bar\\\",\\n\\t\\\"baz\\\": null\\n}\\n```\\n\\nSome more text.\\n\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {},\n        \"version\": \"1.0\"\n    },\n    \"host\": \"\",\n    \"basePath\": \"\",\n    \"paths\": {\n        \"/random\": {\n            \"get\": {\n                \"description\": \"# Title with \\\"quotes\\\"\\n\\nAs we want to verify that this markdown is formatted equally in both the general\\nAPI description, in a tag description and in an endpoint description, the tag\\ndefined in main.go is called api, and the markdown file name is specified\\nmanually in the description comment in api/api.go.\\n\\n```json\\n{\\n\\t\\\"with\\\": \\\"escaped \\\\\\\"quotes\\\\\\\"\\\",\\n\\t\\\"indentedWith\\\": \\\"tabs\\\",\\n\\t\\\"foo\\\": \\\"bar\\\",\\n\\t\\\"baz\\\": null\\n}\\n```\\n\\nSome more text.\\n\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"tags\": [\n        {\n            \"description\": \"# Title with \\\"quotes\\\"\\n\\nAs we want to verify that this markdown is formatted equally in both the general\\nAPI description, in a tag description and in an endpoint description, the tag\\ndefined in main.go is called api, and the markdown file name is specified\\nmanually in the description comment in api/api.go.\\n\\n```json\\n{\\n\\t\\\"with\\\": \\\"escaped \\\\\\\"quotes\\\\\\\"\\\",\\n\\t\\\"indentedWith\\\": \\\"tabs\\\",\\n\\t\\\"foo\\\": \\\"bar\\\",\\n\\t\\\"baz\\\": null\\n}\\n```\\n\\nSome more text.\\n\",\n            \"name\": \"api\"\n        }\n    ]\n}"
  },
  {
    "path": "testdata/quotes/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/swaggo/swag\"\n\t\"github.com/swaggo/swag/testdata/quotes/api\"\n\t_ \"github.com/swaggo/swag/testdata/quotes/docs\"\n)\n\nfunc ReadDoc() string {\n\tdoc, _ := swag.ReadDoc()\n\treturn doc\n}\n\n// @title Swagger Example API\n// @version 1.0\n// @description.markdown\n// @tag.name api\n// @tag.description.markdown\n// @termsOfService http://swagger.io/terms/\n\nfunc main() {\n\tapi.RandomFunc()\n}\n"
  },
  {
    "path": "testdata/recursive_with_name/main.go",
    "content": "package main\n\nimport \"net/http\"\n\n// @title Recursive Type with @name Test API\n// @version 1.0\n// @description This is a test for recursive types with @name annotations\n// @BasePath /api/v1\n\n// EntityHierarchyNode represents a node in the entity hierarchy tree.\n// Each node contains an entity and its child nodes.\ntype EntityHierarchyNode struct {\n\tID       string                 `json:\"id\"`\n\tName     string                 `json:\"name\"`\n\tChildren []*EntityHierarchyNode `json:\"children\"`\n} // @name EntityHierarchyNode\n\n// TreeData represents a complete tree structure\ntype TreeData struct {\n\tRoot EntityHierarchyNode `json:\"root\"`\n} // @name TreeData\n\n// GetEntityHierarchy returns the entity hierarchy\n// @Summary Get entity hierarchy\n// @Description Get the complete entity hierarchy tree\n// @Tags hierarchy\n// @Accept json\n// @Produce json\n// @Success 200 {object} TreeData\n// @Router /hierarchy [get]\nfunc GetEntityHierarchy(w http.ResponseWriter, r *http.Request) {\n\t// Implementation\n}\n\nfunc main() {\n\t// Server setup\n}\n"
  },
  {
    "path": "testdata/simple/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t. \"github.com/swaggo/swag/testdata/simple/cross\"\n\t_ \"github.com/swaggo/swag/testdata/simple/web\"\n)\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @ID get-string-by-int\n// @Accept  json\n// @Produce  json\n// @Param   some_id      path   int     true  \"Some ID\" Format(int64)\n// @Param   some_id      body web.Pet true  \"Some ID\"\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /testapi/get-string-by-int/{some_id} [get]\nfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {\n\t_ = Cross{}\n\t//write your code\n}\n\n// @Description get struct array by ID\n// @ID get-struct-array-by-string\n// @Accept  json\n// @Produce  json\n// @Param some_id path string true \"Some ID\"\n// @Param category query int true \"Category\" Enums(1, 2, 3)\n// @Param offset query int true \"Offset\" Minimum(0) default(0)\n// @Param limit query int true \"Limit\" Maximum(50) default(10)\n// @Param q query string true \"q\" Minlength(1) Maxlength(50) default(\"\")\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Security ApiKeyAuth\n// @Security BasicAuth\n// @Security OAuth2Application[write]\n// @Security OAuth2Implicit[read, admin]\n// @Security OAuth2AccessCode[read]\n// @Security OAuth2Password[admin]\n// @Security OAuth2Implicit[read, write] || Firebase\n// @Router /testapi/get-struct-array-by-string/{some_id} [get]\nfunc GetStructArrayByString(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary Upload file\n// @Description Upload file\n// @ID file.upload\n// @Accept  multipart/form-data\n// @Produce  json\n// @Param   file formData file true  \"this is a test file\"\n// @Success 200 {string} string \"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 401 {array} string\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Failure 403 {object} Cross \"cross\"\n// @Router /file/upload [post]\nfunc Upload(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary use Anonymous field\n// @Success 200 {object} web.RevValue \"ok\"\n// @Router /AnonymousField [get]\nfunc AnonymousField() {\n\n}\n\n// @Summary use pet2\n// @Success 200 {object} web.Pet2 \"ok\"\n// @Router /Pet2 [get]\nfunc Pet2() {\n\n}\n\n// @Summary Use IndirectRecursiveTest\n// @Success 200 {object} web.IndirectRecursiveTest\n// @Router /IndirectRecursiveTest [get]\nfunc IndirectRecursiveTest() {\n}\n\n// @Summary Use Tags\n// @Success 200 {object} web.Tags\n// @Router /Tags [get]\nfunc Tags() {\n}\n\n// @Summary Use CrossAlias\n// @Success 200 {object} web.CrossAlias\n// @Router /CrossAlias [get]\nfunc CrossAlias() {\n}\n\n// @Summary Use AnonymousStructArray\n// @Success 200 {object} web.AnonymousStructArray\n// @Router /AnonymousStructArray [get]\nfunc AnonymousStructArray() {\n}\n\ntype Pet3 struct {\n\tID int `json:\"id\"`\n}\n\n// @Success 200 {object} web.Pet5a \"ok\"\n// @Router /GetPet5a [options]\nfunc GetPet5a() {\n\n}\n\n// @Success 200 {object} web.Pet5b \"ok\"\n// @Router /GetPet5b [head]\nfunc GetPet5b() {\n\n}\n\n// @Success 200 {object} web.Pet5c \"ok\"\n// @Router /GetPet5c [patch]\nfunc GetPet5c() {\n\n}\n\ntype SwagReturn []map[string]string\n\n// @Success 200 {object}  api.SwagReturn\t\"ok\"\n// @Router /GetPet6MapString [get]\nfunc GetPet6MapString() {\n\n}\n\n// @Success 200 {object}  api.GetPet6FunctionScopedResponse.response \"ok\"\n// @Router /GetPet6FunctionScopedResponse [get]\nfunc GetPet6FunctionScopedResponse() {\n\ttype response struct {\n\t\tName string\n\t}\n}\n\n// @Success 200 {object}  api.GetPet6FunctionScopedComplexResponse.response \"ok\"\n// @Router /GetPet6FunctionScopedComplexResponse [get]\nfunc GetPet6FunctionScopedComplexResponse() {\n\ttype pet struct {\n\t\tName string\n\t}\n\n\ttype pointerPet struct {\n\t\tName string\n\t}\n\n\ttype response struct {\n\t\tPets       []pet\n\t\tPointerPet *pointerPet\n\t}\n}\n"
  },
  {
    "path": "testdata/simple/cross/test.go",
    "content": "package cross\n\ntype Cross struct {\n\tArray  []string\n\tString string\n}\n"
  },
  {
    "path": "testdata/simple/expected.json",
    "content": "{\n  \"swagger\": \"2.0\",\n  \"info\": {\n    \"description\": \"This is a sample server Petstore server.\",\n    \"title\": \"Swagger Example API\",\n    \"termsOfService\": \"http://swagger.io/terms/\",\n    \"contact\": {\n      \"name\": \"API Support\",\n      \"url\": \"http://www.swagger.io/support\",\n      \"email\": \"support@swagger.io\"\n    },\n    \"license\": {\n      \"name\": \"Apache 2.0\",\n      \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n    },\n    \"version\": \"1.0\"\n  },\n  \"host\": \"petstore.swagger.io\",\n  \"basePath\": \"/v2\",\n  \"paths\": {\n    \"/AnonymousField\": {\n      \"get\": {\n        \"summary\": \"use Anonymous field\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"ok\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.RevValue\"\n            }\n          }\n        }\n      }\n    },\n    \"/AnonymousStructArray\": {\n      \"get\": {\n        \"summary\": \"Use AnonymousStructArray\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"OK\",\n            \"schema\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"object\",\n                \"properties\": {\n                  \"foo\": {\n                    \"type\": \"string\"\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n    },\n    \"/CrossAlias\": {\n      \"get\": {\n        \"summary\": \"Use CrossAlias\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"OK\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.CrossAlias\"\n            }\n          }\n        }\n      }\n    },\n    \"/GetPet5a\": {\n      \"options\": {\n        \"responses\": {\n          \"200\": {\n            \"description\": \"ok\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.Pet5a\"\n            }\n          }\n        }\n      }\n    },\n    \"/GetPet5b\": {\n      \"head\": {\n        \"responses\": {\n          \"200\": {\n            \"description\": \"ok\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.Pet5b\"\n            }\n          }\n        }\n      }\n    },\n    \"/GetPet5c\": {\n      \"patch\": {\n        \"responses\": {\n          \"200\": {\n            \"description\": \"ok\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.Pet5c\"\n            }\n          }\n        }\n      }\n    },\n    \"/GetPet6FunctionScopedComplexResponse\": {\n      \"get\": {\n        \"responses\": {\n          \"200\": {\n            \"description\": \"ok\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/api.GetPet6FunctionScopedComplexResponse.response\"\n            }\n          }\n        }\n      }\n    },\n    \"/GetPet6FunctionScopedResponse\": {\n      \"get\": {\n        \"responses\": {\n          \"200\": {\n            \"description\": \"ok\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/api.GetPet6FunctionScopedResponse.response\"\n            }\n          }\n        }\n      }\n    },\n    \"/GetPet6MapString\": {\n      \"get\": {\n        \"responses\": {\n          \"200\": {\n            \"description\": \"ok\",\n            \"schema\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"object\",\n                \"additionalProperties\": {\n                  \"type\": \"string\"\n                }\n              }\n            }\n          }\n        }\n      }\n    },\n    \"/IndirectRecursiveTest\": {\n      \"get\": {\n        \"summary\": \"Use IndirectRecursiveTest\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"OK\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.IndirectRecursiveTest\"\n            }\n          }\n        }\n      }\n    },\n    \"/Pet2\": {\n      \"get\": {\n        \"summary\": \"use pet2\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"ok\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.Pet2\"\n            }\n          }\n        }\n      }\n    },\n    \"/Tags\": {\n      \"get\": {\n        \"summary\": \"Use Tags\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"OK\",\n            \"schema\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/definitions/web.Tag\"\n              }\n            }\n          }\n        }\n      }\n    },\n    \"/file/upload\": {\n      \"post\": {\n        \"description\": \"Upload file\",\n        \"consumes\": [\n          \"multipart/form-data\"\n        ],\n        \"produces\": [\n          \"application/json\"\n        ],\n        \"summary\": \"Upload file\",\n        \"operationId\": \"file.upload\",\n        \"parameters\": [\n          {\n            \"type\": \"file\",\n            \"description\": \"this is a test file\",\n            \"name\": \"file\",\n            \"in\": \"formData\",\n            \"required\": true\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"ok\",\n            \"schema\": {\n              \"type\": \"string\"\n            }\n          },\n          \"400\": {\n            \"description\": \"We need ID!!\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.APIError\"\n            }\n          },\n          \"401\": {\n            \"description\": \"Unauthorized\",\n            \"schema\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          },\n          \"403\": {\n            \"description\": \"cross\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/cross.Cross\"\n            }\n          },\n          \"404\": {\n            \"description\": \"Can not find ID\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.APIError\"\n            }\n          }\n        }\n      }\n    },\n    \"/testapi/get-string-by-int/{some_id}\": {\n      \"get\": {\n        \"description\": \"get string by ID\",\n        \"consumes\": [\n          \"application/json\"\n        ],\n        \"produces\": [\n          \"application/json\"\n        ],\n        \"summary\": \"Add a new pet to the store\",\n        \"operationId\": \"get-string-by-int\",\n        \"parameters\": [\n          {\n            \"type\": \"integer\",\n            \"format\": \"int64\",\n            \"description\": \"Some ID\",\n            \"name\": \"some_id\",\n            \"in\": \"path\",\n            \"required\": true\n          },\n          {\n            \"description\": \"Some ID\",\n            \"name\": \"some_id\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.Pet\"\n            }\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"ok\",\n            \"schema\": {\n              \"type\": \"string\"\n            }\n          },\n          \"400\": {\n            \"description\": \"We need ID!!\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.APIError\"\n            }\n          },\n          \"404\": {\n            \"description\": \"Can not find ID\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.APIError\"\n            }\n          }\n        }\n      }\n    },\n    \"/testapi/get-struct-array-by-string/{some_id}\": {\n      \"get\": {\n        \"security\": [\n          {\n            \"ApiKeyAuth\": []\n          },\n          {\n            \"BasicAuth\": []\n          },\n          {\n            \"OAuth2Application\": [\n              \"write\"\n            ]\n          },\n          {\n            \"OAuth2Implicit\": [\n              \"read\",\n              \"admin\"\n            ]\n          },\n          {\n            \"OAuth2AccessCode\": [\n              \"read\"\n            ]\n          },\n          {\n            \"OAuth2Password\": [\n              \"admin\"\n            ]\n          },\n          {\n            \"Firebase\": [],\n            \"OAuth2Implicit\": [\n              \"read\",\n              \"write\"\n            ]\n          }\n        ],\n        \"description\": \"get struct array by ID\",\n        \"consumes\": [\n          \"application/json\"\n        ],\n        \"produces\": [\n          \"application/json\"\n        ],\n        \"operationId\": \"get-struct-array-by-string\",\n        \"parameters\": [\n          {\n            \"type\": \"string\",\n            \"description\": \"Some ID\",\n            \"name\": \"some_id\",\n            \"in\": \"path\",\n            \"required\": true\n          },\n          {\n            \"enum\": [\n              1,\n              2,\n              3\n            ],\n            \"type\": \"integer\",\n            \"description\": \"Category\",\n            \"name\": \"category\",\n            \"in\": \"query\",\n            \"required\": true\n          },\n          {\n            \"minimum\": 0,\n            \"type\": \"integer\",\n            \"default\": 0,\n            \"description\": \"Offset\",\n            \"name\": \"offset\",\n            \"in\": \"query\",\n            \"required\": true\n          },\n          {\n            \"maximum\": 50,\n            \"type\": \"integer\",\n            \"default\": 10,\n            \"description\": \"Limit\",\n            \"name\": \"limit\",\n            \"in\": \"query\",\n            \"required\": true\n          },\n          {\n            \"maxLength\": 50,\n            \"minLength\": 1,\n            \"type\": \"string\",\n            \"default\": \"\\\"\\\"\",\n            \"description\": \"q\",\n            \"name\": \"q\",\n            \"in\": \"query\",\n            \"required\": true\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"ok\",\n            \"schema\": {\n              \"type\": \"string\"\n            }\n          },\n          \"400\": {\n            \"description\": \"We need ID!!\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.APIError\"\n            }\n          },\n          \"404\": {\n            \"description\": \"Can not find ID\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/web.APIError\"\n            }\n          }\n        }\n      }\n    }\n  },\n  \"definitions\": {\n    \"api.GetPet6FunctionScopedComplexResponse.pet\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Name\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"api.GetPet6FunctionScopedComplexResponse.pointerPet\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Name\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"api.GetPet6FunctionScopedComplexResponse.response\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Pets\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/api.GetPet6FunctionScopedComplexResponse.pet\"\n          }\n        },\n        \"PointerPet\": {\n          \"$ref\": \"#/definitions/api.GetPet6FunctionScopedComplexResponse.pointerPet\"\n        }\n      }\n    },\n    \"api.GetPet6FunctionScopedResponse.response\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Name\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"cross.Cross\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Array\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"String\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"web.APIError\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"CreatedAt\": {\n          \"type\": \"string\"\n        },\n        \"ErrorCode\": {\n          \"type\": \"integer\"\n        },\n        \"ErrorMessage\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"web.CrossAlias\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Array\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"String\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"web.IndirectRecursiveTest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Tags\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/web.Tag\"\n          }\n        }\n      }\n    },\n    \"web.Pet\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"name\",\n        \"photo_urls\"\n      ],\n      \"properties\": {\n        \"category\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"id\": {\n              \"type\": \"integer\",\n              \"example\": 1\n            },\n            \"name\": {\n              \"type\": \"string\",\n              \"example\": \"category_name\"\n            },\n            \"photo_urls\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\",\n                \"format\": \"url\"\n              },\n              \"example\": [\n                \"http://test/image/1.jpg\",\n                \"http://test/image/2.jpg\"\n              ]\n            },\n            \"small_category\": {\n              \"type\": \"object\",\n              \"required\": [\n                \"name\"\n              ],\n              \"properties\": {\n                \"id\": {\n                  \"type\": \"integer\",\n                  \"example\": 1\n                },\n                \"name\": {\n                  \"type\": \"string\",\n                  \"maxLength\": 16,\n                  \"minLength\": 4,\n                  \"example\": \"detail_category_name\"\n                },\n                \"photo_urls\": {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"type\": \"string\"\n                  },\n                  \"example\": [\n                    \"http://test/image/1.jpg\",\n                    \"http://test/image/2.jpg\"\n                  ]\n                }\n              }\n            }\n          }\n        },\n        \"data\": {},\n        \"decimal\": {\n          \"type\": \"number\"\n        },\n        \"enum_array\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"integer\",\n            \"enum\": [\n              1,\n              2,\n              3,\n              5,\n              7\n            ]\n          }\n        },\n        \"food_brands\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"x-some-extension\": true\n        },\n        \"food_types\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"integer\",\n            \"enum\": [\n              0,\n              1,\n              2\n            ],\n            \"x-enum-varnames\": [\n              \"Wet\",\n              \"Dry\",\n              \"Raw\"\n            ]\n          },\n          \"x-some-extension\": true\n        },\n        \"id\": {\n          \"type\": \"integer\",\n          \"format\": \"int64\",\n          \"readOnly\": true,\n          \"example\": 1\n        },\n        \"int_array\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"integer\"\n          },\n          \"example\": [\n            1,\n            2\n          ]\n        },\n        \"is_alive\": {\n          \"type\": \"boolean\",\n          \"default\": true,\n          \"example\": true\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"example\": \"poti\"\n        },\n        \"pets\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/web.Pet2\"\n          }\n        },\n        \"pets2\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/web.Pet2\"\n          }\n        },\n        \"photo_urls\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"example\": [\n            \"http://test/image/1.jpg\",\n            \"http://test/image/2.jpg\"\n          ]\n        },\n        \"price\": {\n          \"type\": \"number\",\n          \"maximum\": 1000,\n          \"minimum\": 1,\n          \"multipleOf\": 0.01,\n          \"example\": 3.25\n        },\n        \"single_enum_varname\": {\n          \"type\": \"integer\",\n          \"enum\": [\n            1,\n            2,\n            3\n          ],\n          \"x-enum-varnames\": [\n            \"one\",\n            \"two\",\n            \"three\"\n          ],\n          \"x-some-extension\": true\n        },\n        \"status\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"healthy\",\n            \"ill\"\n          ]\n        },\n        \"string_map\": {\n          \"type\": \"object\",\n          \"additionalProperties\": {\n            \"type\": \"string\"\n          },\n          \"example\": {\n            \"key1\": \"value\",\n            \"key2\": \"value2\"\n          }\n        },\n        \"tags\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/web.Tag\"\n          }\n        },\n        \"uuid\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"web.Pet2\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"deleted_at\": {\n          \"type\": \"string\"\n        },\n        \"id\": {\n          \"type\": \"integer\"\n        },\n        \"middlename\": {\n          \"type\": \"string\",\n          \"x-abc\": \"def\",\n          \"x-nullable\": true,\n          \"x-omitempty\": false\n        }\n      }\n    },\n    \"web.Pet5a\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"name\",\n        \"odd\"\n      ],\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\"\n        },\n        \"odd\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"web.Pet5b\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"name\"\n      ],\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"web.Pet5c\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"name\",\n        \"odd\"\n      ],\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\"\n        },\n        \"odd\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"web.RevValue\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Data\": {\n          \"type\": \"integer\"\n        },\n        \"cross\": {\n          \"$ref\": \"#/definitions/cross.Cross\"\n        },\n        \"crosses\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/cross.Cross\"\n          }\n        },\n        \"rev_value_base\": {\n          \"$ref\": \"#/definitions/web.RevValueBase\"\n        }\n      }\n    },\n    \"web.RevValueBase\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Err\": {\n          \"type\": \"integer\"\n        },\n        \"Status\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"web.Tag\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"id\": {\n          \"type\": \"integer\",\n          \"format\": \"int64\"\n        },\n        \"name\": {\n          \"type\": \"string\"\n        },\n        \"pets\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/web.Pet\"\n          }\n        }\n      }\n    }\n  },\n  \"securityDefinitions\": {\n    \"ApiKeyAuth\": {\n      \"type\": \"apiKey\",\n      \"name\": \"Authorization\",\n      \"in\": \"header\"\n    },\n    \"BasicAuth\": {\n      \"type\": \"basic\"\n    },\n    \"OAuth2AccessCode\": {\n      \"type\": \"oauth2\",\n      \"flow\": \"accessCode\",\n      \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n      \"tokenUrl\": \"https://example.com/oauth/token\",\n      \"scopes\": {\n        \"admin\": \"Grants read and write access to administrative information\"\n      }\n    },\n    \"OAuth2Application\": {\n      \"type\": \"oauth2\",\n      \"flow\": \"application\",\n      \"tokenUrl\": \"https://example.com/oauth/token\",\n      \"scopes\": {\n        \"admin\": \"Grants read and write access to administrative information\",\n        \"write\": \"Grants write access\"\n      }\n    },\n    \"OAuth2Implicit\": {\n      \"type\": \"oauth2\",\n      \"flow\": \"implicit\",\n      \"authorizationUrl\": \"https://example.com/oauth/authorize\",\n      \"scopes\": {\n        \"admin\": \"Grants read and write access to administrative information\",\n        \"write\": \"Grants write access\"\n      }\n    },\n    \"OAuth2Password\": {\n      \"type\": \"oauth2\",\n      \"flow\": \"password\",\n      \"tokenUrl\": \"https://example.com/oauth/token\",\n      \"scopes\": {\n        \"admin\": \"Grants read and write access to administrative information\",\n        \"read\": \"Grants read access\",\n        \"write\": \"Grants write access\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "testdata/simple/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/simple/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\n// @securityDefinitions.basic BasicAuth\n\n// @securityDefinitions.apikey ApiKeyAuth\n// @in header\n// @name Authorization\n\n// @securitydefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.implicit OAuth2Implicit\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.password OAuth2Password\n// @tokenUrl https://example.com/oauth/token\n// @scope.read Grants read access\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.accessCode OAuth2AccessCode\n// @tokenUrl https://example.com/oauth/token\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.admin Grants read and write access to administrative information\nfunc main() {\n\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\thttp.HandleFunc(\"/testapi/get-struct-array-by-string/\", api.GetStructArrayByString)\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/simple/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n\n\t\"github.com/gofrs/uuid\"\n\t\"github.com/shopspring/decimal\"\n\t\"github.com/swaggo/swag/testdata/simple/cross\"\n)\n\ntype Pet struct {\n\tID       int `json:\"id\" example:\"1\" format:\"int64\" readonly:\"true\"`\n\tCategory struct {\n\t\tID            int      `json:\"id\" example:\"1\"`\n\t\tName          string   `json:\"name\" example:\"category_name\"`\n\t\tPhotoUrls     []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\" format:\"url\"`\n\t\tSmallCategory struct {\n\t\t\tID        int      `json:\"id\" example:\"1\"`\n\t\t\tName      string   `json:\"name\" example:\"detail_category_name\" binding:\"required\" minLength:\"4\" maxLength:\"16\"`\n\t\t\tPhotoUrls []string `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\t\t} `json:\"small_category\"`\n\t} `json:\"category\"`\n\tName              string            `json:\"name\" example:\"poti\" binding:\"required\"`\n\tPhotoUrls         []string          `json:\"photo_urls\" example:\"http://test/image/1.jpg,http://test/image/2.jpg\" binding:\"required\"`\n\tTags              []Tag             `json:\"tags\"`\n\tPets              *[]Pet2           `json:\"pets\"`\n\tPets2             []*Pet2           `json:\"pets2\"`\n\tStatus            string            `json:\"status\" enums:\"healthy,ill\"`\n\tPrice             float32           `json:\"price\" example:\"3.25\" minimum:\"1.0\" maximum:\"1000\" multipleOf:\"0.01\"`\n\tIsAlive           bool              `json:\"is_alive\" example:\"true\" default:\"true\"`\n\tData              interface{}       `json:\"data\"`\n\tHidden            string            `json:\"-\"`\n\tUUID              uuid.UUID         `json:\"uuid\"`\n\tDecimal           decimal.Decimal   `json:\"decimal\"`\n\tIntArray          []int             `json:\"int_array\" example:\"1,2\"`\n\tStringMap         map[string]string `json:\"string_map\" example:\"key1:value,key2:value2\"`\n\tEnumArray         []int             `json:\"enum_array\" enums:\"1,2,3,5,7\"`\n\tFoodTypes         []string          `json:\"food_types\" swaggertype:\"array,integer\" enums:\"0,1,2\" x-enum-varnames:\"Wet,Dry,Raw\" extensions:\"x-some-extension\"`\n\tFoodBrands        []string          `json:\"food_brands\" extensions:\"x-some-extension\"`\n\tSingleEnumVarname string            `json:\"single_enum_varname\" swaggertype:\"integer\" enums:\"1,2,3\" x-enum-varnames:\"one,two,three\" extensions:\"x-some-extension\"`\n}\n\ntype Tag struct {\n\tID   int    `json:\"id\" format:\"int64\"`\n\tName string `json:\"name\"`\n\tPets []Pet  `json:\"pets\"`\n}\n\ntype Tags []*Tag\n\ntype AnonymousStructArray []struct {\n\tFoo string `json:\"foo\"`\n}\n\ntype CrossAlias cross.Cross\n\ntype Pet2 struct {\n\tID         int        `json:\"id\"`\n\tMiddleName *string    `json:\"middlename\" extensions:\"x-nullable,x-abc=def,!x-omitempty\"`\n\tDeletedAt  *time.Time `json:\"deleted_at\"`\n}\n\ntype IndirectRecursiveTest struct {\n\tTags []Tag\n}\n\ntype APIError struct {\n\tErrorCode    int\n\tErrorMessage string\n\tCreatedAt    time.Time\n}\n\ntype RevValueBase struct {\n\tStatus bool `json:\"Status\"`\n\n\tErr int32 `json:\"Err,omitempty\"`\n}\ntype RevValue struct {\n\tRevValueBase `json:\"rev_value_base\"`\n\n\tData    int           `json:\"Data\"`\n\tCross   cross.Cross   `json:\"cross\"`\n\tCrosses []cross.Cross `json:\"crosses\"`\n}\n\n// Below we have Pet5b as base type and Pet5a and Pet5c both have Pet5b as anonymous field, inheriting it's properties\n// By using these names we ensure that our test will fill if the order of parsing matters at all\n\ntype Pet5a struct {\n\t*Pet5b\n\tOdd bool `json:\"odd\" binding:\"required\"`\n}\n\ntype Pet5b struct {\n\tName string `json:\"name\" binding:\"required\"`\n}\n\ntype Pet5c struct {\n\t*Pet5b\n\tOdd bool `json:\"odd\" binding:\"required\"`\n}\n"
  },
  {
    "path": "testdata/simple2/api/api.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n)\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @ID get-string-by-int\n// @Accept  json\n// @Produce  json\n// @Param   some_id      path   int     true  \"Some ID\" Format(int64)\n// @Param   some_id      body web.Pet true  \"Some ID\"\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /testapi/get-string-by-int/{some_id} [get]\nfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Description get struct array by ID\n// @ID get-struct-array-by-string\n// @Accept  json\n// @Produce  json\n// @Param some_id path string true \"Some ID\"\n// @Param category query int true \"Category\" Enums(1, 2, 3)\n// @Param offset query int true \"Offset\" Minimum(0) default(0)\n// @Param limit query int true \"Limit\" Maximum(50) default(10)\n// @Param q query string true \"q\" Minlength(1) Maxlength(50) default(\"\")\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Security ApiKeyAuth\n// @Security BasicAuth\n// @Security OAuth2Application[write]\n// @Security OAuth2Implicit[read, admin]\n// @Security OAuth2AccessCode[read]\n// @Security OAuth2Password[admin]\n// @Router /testapi/get-struct-array-by-string/{some_id} [get]\nfunc GetStructArrayByString(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary Upload file\n// @Description Upload file\n// @ID file.upload\n// @Accept  multipart/form-data\n// @Produce  json\n// @Param   file formData file true  \"this is a test file\"\n// @Success 200 {string} string \"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /file/upload [post]\nfunc Upload(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary use Anonymous field\n// @Success 200 {object} web.RevValue \"ok\"\nfunc AnonymousField() {\n\n}\n\n// @Summary use pet2\n// @Success 200 {object} web.Pet2 \"ok\"\nfunc Pet2() {\n\n}\n\ntype Pet3 struct {\n\tID int `json:\"id\"`\n}\n"
  },
  {
    "path": "testdata/simple2/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/simple2/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\n// @securityDefinitions.basic BasicAuth\n\n// @securityDefinitions.apikey ApiKeyAuth\n// @in header\n// @name Authorization\n\n// @securitydefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.implicit OAuth2Implicit\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.password OAuth2Password\n// @tokenUrl https://example.com/oauth/token\n// @scope.read Grants read access\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.accessCode OAuth2AccessCode\n// @tokenUrl https://example.com/oauth/token\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.admin Grants read and write access to administrative information\nfunc main() {\n\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\thttp.HandleFunc(\"//testapi/get-struct-array-by-string/\", api.GetStructArrayByString)\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/simple2/web/handler.go",
    "content": "package web\n\nimport (\n\t\"database/sql\"\n\t\"math/big\"\n\t\"strconv\"\n\t\"time\"\n\n\tuuid \"github.com/gofrs/uuid\"\n\t\"github.com/shopspring/decimal\"\n)\n\ntype TimestampTime struct {\n\ttime.Time\n}\n\nfunc (t *TimestampTime) MarshalJSON() ([]byte, error) {\n\tbin := make([]byte, 16)\n\tbin = strconv.AppendInt(bin[:0], t.Time.Unix(), 10)\n\treturn bin, nil\n}\n\nfunc (t *TimestampTime) UnmarshalJSON(bin []byte) error {\n\tv, err := strconv.ParseInt(string(bin), 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\tt.Time = time.Unix(v, 0)\n\treturn nil\n}\n\ntype Pet struct {\n\tID       int `example:\"1\" format:\"int64\"`\n\tCategory struct {\n\t\tID            int      `example:\"1\"`\n\t\tName          string   `example:\"category_name\"`\n\t\tPhotoUrls     []string `example:\"http://test/image/1.jpg,http://test/image/2.jpg\" format:\"url\"`\n\t\tSmallCategory struct {\n\t\t\tID        int      `example:\"1\"`\n\t\t\tName      string   `example:\"detail_category_name\" validate:\"required\"`\n\t\t\tPhotoUrls []string `example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\t\t}\n\t}\n\tName            string   `example:\"poti\"`\n\tPhotoUrls       []string `example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\tTags            []Tag\n\tPets            *[]Pet2\n\tPets2           []*Pet2\n\tStatus          string\n\tPrice           float32 `example:\"3.25\" validate:\"required,gte=0,lte=130\" multipleOf:\"0.01\"`\n\tIsAlive         bool    `example:\"true\"`\n\tData            interface{}\n\tHidden          string `json:\"-\"`\n\tUUID            uuid.UUID\n\tDecimal         decimal.Decimal\n\tCustomString    CustomString\n\tCustomStringArr []CustomString\n\tNullInt         sql.NullInt64 `swaggertype:\"integer\"`\n\tCoeffs          []big.Float   `swaggertype:\"array,number\"`\n\tBirthday        TimestampTime `swaggertype:\"primitive,integer\"`\n}\n\ntype CustomString string\n\ntype Tag struct {\n\tID   int `format:\"int64\"`\n\tName string\n\tPets []Pet\n}\n\ntype Pet2 struct {\n\tID         int\n\tMiddleName *string\n\tDeletedAt  *time.Time\n}\n\ntype APIError struct {\n\tErrorCode    int\n\tErrorMessage string\n\tCreatedAt    time.Time\n}\n\ntype RevValueBase struct {\n\tStatus bool\n\n\tErr int32\n}\ntype RevValue struct {\n\tRevValueBase\n\n\tData int\n}\n"
  },
  {
    "path": "testdata/simple3/api/api.go",
    "content": "package api\n\nimport \"net/http\"\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @ID get-string-by-int\n// @Accept  json\n// @Produce  json\n// @Param   some_id      path   int     true  \"Some ID\" Format(int64)\n// @Param   some_id      body web.Pet true  \"Some ID\"\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /testapi/get-string-by-int/{some_id} [get]\nfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Description get struct array by ID\n// @ID get-struct-array-by-string\n// @Accept  json\n// @Produce  json\n// @Param some_id path string true \"Some ID\"\n// @Param category query int true \"Category\" Enums(1, 2, 3)\n// @Param offset query int true \"Offset\" Minimum(0) default(0)\n// @Param limit query int true \"Limit\" Maximum(50) default(10)\n// @Param q query string true \"q\" Minlength(1) Maxlength(50) default(\"\")\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Security ApiKeyAuth\n// @Security BasicAuth\n// @Security OAuth2Application[write]\n// @Security OAuth2Implicit[read, admin]\n// @Security OAuth2AccessCode[read]\n// @Security OAuth2Password[admin]\n// @Router /testapi/get-struct-array-by-string/{some_id} [get]\nfunc GetStructArrayByString(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary Upload file\n// @Description Upload file\n// @ID file.upload\n// @Accept  multipart/form-data\n// @Produce  json\n// @Param   file formData file true  \"this is a test file\"\n// @Success 200 {string} string \"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /file/upload [post]\nfunc Upload(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @Summary use Anonymous field\n// @Success 200 {object} web.RevValue \"ok\"\nfunc AnonymousField() {\n\n}\n\n// @Summary use pet2\n// @Success 200 {object} web.Pet2 \"ok\"\nfunc Pet2() {\n\n}\n\ntype Pet3 struct {\n\tID int `json:\"id\"`\n}\n"
  },
  {
    "path": "testdata/simple3/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/simple3/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\n// @securityDefinitions.basic BasicAuth\n\n// @securityDefinitions.apikey ApiKeyAuth\n// @in header\n// @name Authorization\n\n// @securitydefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.implicit OAuth2Implicit\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.password OAuth2Password\n// @tokenUrl https://example.com/oauth/token\n// @scope.read Grants read access\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.accessCode OAuth2AccessCode\n// @tokenUrl https://example.com/oauth/token\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.admin Grants read and write access to administrative information\nfunc main() {\n\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\thttp.HandleFunc(\"//testapi/get-struct-array-by-string/\", api.GetStructArrayByString)\n\thttp.HandleFunc(\"/testapi/upload\", api.Upload)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/simple3/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n\n\tuuid \"github.com/gofrs/uuid\"\n\t\"github.com/shopspring/decimal\"\n)\n\ntype Pet struct {\n\tID       int `example:\"1\" format:\"int64\"`\n\tCategory struct {\n\t\tID            int      `example:\"1\"`\n\t\tName          string   `example:\"category_name\"`\n\t\tPhotoURLs     []string `example:\"http://test/image/1.jpg,http://test/image/2.jpg\" format:\"url\"`\n\t\tSmallCategory struct {\n\t\t\tID        int      `example:\"1\"`\n\t\t\tName      string   `example:\"detail_category_name\"`\n\t\t\tPhotoURLs []string `example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\t\t}\n\t}\n\tName      string   `example:\"poti\"`\n\tPhotoURLs []string `example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\tTags      []Tag\n\tPets      *[]Pet2\n\tPets2     []*Pet2\n\tStatus    string\n\tPrice     float32 `example:\"3.25\" multipleOf:\"0.01\"`\n\tIsAlive   bool    `example:\"true\"`\n\tData      interface{}\n\tHidden    string `json:\"-\"`\n\tUUID      uuid.UUID\n\tDecimal   decimal.Decimal\n\tFunction  func()\n}\n\ntype Tag struct {\n\tID   int `format:\"int64\"`\n\tName string\n\tPets []Pet\n}\n\ntype Pet2 struct {\n\tID         int\n\tMiddleName *string\n\tDeletedAt  *time.Time\n}\n\ntype APIError struct {\n\tErrorCode    int\n\tErrorMessage string\n\tCreatedAt    time.Time\n}\n\ntype RevValueBase struct {\n\tStatus bool\n\n\tErr int32\n}\ntype RevValue struct {\n\tRevValueBase\n\n\tData int\n}\n"
  },
  {
    "path": "testdata/simple_cgo/api/api.go",
    "content": "package api\n\nimport \"net/http\"\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @ID get-string-by-int\n// @Accept  json\n// @Produce  json\n// @Param   some_id      path   int     true  \"Some ID\" Format(int64)\n// @Param   some_id      body   int     true  \"Some ID\"\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} string \"We need ID!!\"\n// @Failure 404 {object} string \"Can not find ID\"\n// @Router /testapi/get-string-by-int/{some_id} [get]\nfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {\n}\n"
  },
  {
    "path": "testdata/simple_cgo/main.go",
    "content": "package main\n\n/*\n#include <stdio.h>\n\nvoid Hello(){\n    printf(\"Hello world\\n\");\n}\n*/\nimport \"C\"\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/simple_cgo/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @host petstore.swagger.io\n// @BasePath /v2\n\n// @securityDefinitions.basic BasicAuth\n\n// @securityDefinitions.apikey ApiKeyAuth\n// @in header\n// @name Authorization\n\n// @securitydefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.implicit OAuth2Implicit\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.password OAuth2Password\n// @tokenUrl https://example.com/oauth/token\n// @scope.read Grants read access\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.accessCode OAuth2AccessCode\n// @tokenUrl https://example.com/oauth/token\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.admin Grants read and write access to administrative information\nfunc main() {\n\tC.Hello()\n\n\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByInt)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/single_file_api/main.go",
    "content": "package main\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @description It has a lot of beautiful features.\n// @termsOfService http://swagger.io/terms/\n\n// @Summary test op\n// @Router /test [get]\n// @Description This belongs to the operation, not the general API!\nfunc op() bool {\n\treturn true\n}\n"
  },
  {
    "path": "testdata/state/admin_expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore-admin.swagger.io\",\n    \"basePath\": \"/v3\",\n    \"paths\": {\n        \"/admin/file/upload\": {\n            \"post\": {\n                \"description\": \"Upload file\",\n                \"consumes\": [\n                    \"multipart/form-data\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Upload file\",\n                \"operationId\": \"admin.file.upload\",\n                \"parameters\": [\n                    {\n                        \"type\": \"file\",\n                        \"description\": \"this is a test file\",\n                        \"name\": \"file\",\n                        \"in\": \"formData\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/admin/testapi/get-string-by-int/{some_id}\": {\n            \"get\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add a new pet to the store\",\n                \"operationId\": \"admin.get-string-by-int\",\n                \"parameters\": [\n                    {\n                        \"type\": \"integer\",\n                        \"format\": \"int64\",\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    },\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.Pet\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/admin/testapi/get-struct-array-by-string/{some_id}\": {\n            \"get\": {\n                \"security\": [\n                    {\n                        \"ApiKeyAuth\": []\n                    },\n                    {\n                        \"BasicAuth\": []\n                    },\n                    {\n                        \"OAuth2Application\": [\n                            \"write\"\n                        ]\n                    },\n                    {\n                        \"OAuth2Implicit\": [\n                            \"read\",\n                            \"admin\"\n                        ]\n                    },\n                    {\n                        \"OAuth2AccessCode\": [\n                            \"read\"\n                        ]\n                    },\n                    {\n                        \"OAuth2Password\": [\n                            \"admin\"\n                        ]\n                    }\n                ],\n                \"description\": \"get struct array by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"operationId\": \"admin.get-struct-array-by-string\",\n                \"parameters\": [\n                    {\n                        \"type\": \"string\",\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    },\n                    {\n                        \"enum\": [\n                            1,\n                            2,\n                            3\n                        ],\n                        \"type\": \"integer\",\n                        \"description\": \"Category\",\n                        \"name\": \"category\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"minimum\": 0,\n                        \"type\": \"integer\",\n                        \"default\": 0,\n                        \"description\": \"Offset\",\n                        \"name\": \"offset\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"maximum\": 50,\n                        \"type\": \"integer\",\n                        \"default\": 10,\n                        \"description\": \"Limit\",\n                        \"name\": \"limit\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"maxLength\": 50,\n                        \"minLength\": 1,\n                        \"type\": \"string\",\n                        \"default\": \"\\\"\\\"\",\n                        \"description\": \"q\",\n                        \"name\": \"q\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"web.APIError\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"createdAt\": {\n                    \"type\": \"string\"\n                },\n                \"errorCode\": {\n                    \"type\": \"integer\"\n                },\n                \"errorMessage\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.Pet\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"category\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"id\": {\n                            \"type\": \"integer\",\n                            \"example\": 1\n                        },\n                        \"name\": {\n                            \"type\": \"string\",\n                            \"example\": \"category_name\"\n                        },\n                        \"photoURLs\": {\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"string\",\n                                \"format\": \"url\"\n                            },\n                            \"example\": [\n                                \"http://test/image/1.jpg\",\n                                \"http://test/image/2.jpg\"\n                            ]\n                        },\n                        \"smallCategory\": {\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"id\": {\n                                    \"type\": \"integer\",\n                                    \"example\": 1\n                                },\n                                \"name\": {\n                                    \"type\": \"string\",\n                                    \"example\": \"detail_category_name\"\n                                },\n                                \"photoURLs\": {\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"type\": \"string\"\n                                    },\n                                    \"example\": [\n                                        \"http://test/image/1.jpg\",\n                                        \"http://test/image/2.jpg\"\n                                    ]\n                                }\n                            }\n                        }\n                    }\n                },\n                \"data\": {},\n                \"decimal\": {\n                    \"type\": \"number\"\n                },\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\",\n                    \"example\": 1\n                },\n                \"isAlive\": {\n                    \"type\": \"boolean\",\n                    \"example\": true\n                },\n                \"name\": {\n                    \"type\": \"string\",\n                    \"example\": \"poti\"\n                },\n                \"pets\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet2\"\n                    }\n                },\n                \"pets2\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet2\"\n                    }\n                },\n                \"photoURLs\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    },\n                    \"example\": [\n                        \"http://test/image/1.jpg\",\n                        \"http://test/image/2.jpg\"\n                    ]\n                },\n                \"price\": {\n                    \"type\": \"number\",\n                    \"multipleOf\": 0.01,\n                    \"example\": 3.25\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                },\n                \"tags\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Tag\"\n                    }\n                },\n                \"uuid\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.Pet2\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"deletedAt\": {\n                    \"type\": \"string\"\n                },\n                \"id\": {\n                    \"type\": \"integer\"\n                },\n                \"middleName\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.RevValue\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"integer\"\n                },\n                \"err\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int32\"\n                },\n                \"status\": {\n                    \"type\": \"boolean\"\n                }\n            }\n        },\n        \"web.Tag\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                },\n                \"pets\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet\"\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/state/api/api.go",
    "content": "package api\n\nimport \"net/http\"\n\n// @State admin\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @ID admin.get-string-by-int\n// @Accept  json\n// @Produce  json\n// @Param   some_id      path   int     true  \"Some ID\" Format(int64)\n// @Param   some_id      body web.Pet true  \"Some ID\"\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /admin/testapi/get-string-by-int/{some_id} [get]\nfunc GetStringByInt(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @State admin\n// @Description get struct array by ID\n// @ID admin.get-struct-array-by-string\n// @Accept  json\n// @Produce  json\n// @Param some_id path string true \"Some ID\"\n// @Param category query int true \"Category\" Enums(1, 2, 3)\n// @Param offset query int true \"Offset\" Minimum(0) default(0)\n// @Param limit query int true \"Limit\" Maximum(50) default(10)\n// @Param q query string true \"q\" Minlength(1) Maxlength(50) default(\"\")\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Security ApiKeyAuth\n// @Security BasicAuth\n// @Security OAuth2Application[write]\n// @Security OAuth2Implicit[read, admin]\n// @Security OAuth2AccessCode[read]\n// @Security OAuth2Password[admin]\n// @Router /admin/testapi/get-struct-array-by-string/{some_id} [get]\nfunc GetStructArrayByString(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @State admin\n// @Summary Upload file\n// @Description Upload file\n// @ID admin.file.upload\n// @Accept  multipart/form-data\n// @Produce  json\n// @Param   file formData file true  \"this is a test file\"\n// @Success 200 {string} string \"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /admin/file/upload [post]\nfunc Upload(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @State admin\n// @Summary use Anonymous field\n// @Success 200 {object} web.RevValue \"ok\"\nfunc AnonymousField() {\n\n}\n\n// @State admin\n// @Summary use pet2\n// @Success 200 {object} web.Pet2 \"ok\"\nfunc Pet2() {\n\n}\n\ntype Pet3 struct {\n\tID int `json:\"id\"`\n}\n"
  },
  {
    "path": "testdata/state/api/api_user.go",
    "content": "package api\n\nimport \"net/http\"\n\n// @State user\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @ID get-string-by-int\n// @Accept  json\n// @Produce  json\n// @Param   some_id      path   int     true  \"Some ID\" Format(int64)\n// @Param   some_id      body web.Pet true  \"Some ID\"\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /testapi/get-string-by-int/{some_id} [get]\nfunc GetStringByIntUser(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @State user\n// @Description get struct array by ID\n// @ID get-struct-array-by-string\n// @Accept  json\n// @Produce  json\n// @Param some_id path string true \"Some ID\"\n// @Param category query int true \"Category\" Enums(1, 2, 3)\n// @Param offset query int true \"Offset\" Minimum(0) default(0)\n// @Param limit query int true \"Limit\" Maximum(50) default(10)\n// @Param q query string true \"q\" Minlength(1) Maxlength(50) default(\"\")\n// @Success 200 {string} string\t\"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Security ApiKeyAuth\n// @Security BasicAuth\n// @Security OAuth2Application[write]\n// @Security OAuth2Implicit[read, admin]\n// @Security OAuth2AccessCode[read]\n// @Security OAuth2Password[admin]\n// @Router /testapi/get-struct-array-by-string/{some_id} [get]\nfunc GetStructArrayByStringUser(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @State user\n// @Summary Upload file\n// @Description Upload file\n// @ID file.upload\n// @Accept  multipart/form-data\n// @Produce  json\n// @Param   file formData file true  \"this is a test file\"\n// @Success 200 {string} string \"ok\"\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /file/upload [post]\nfunc UploadUser(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n\n// @State user\n// @Summary use Anonymous field\n// @Success 200 {object} web.RevValue \"ok\"\nfunc AnonymousFieldUser() {\n\n}\n\n// @State user\n// @Summary use pet2\n// @Success 200 {object} web.Pet2 \"ok\"\nfunc Pet2User() {\n\n}\n\ntype Pet3User struct {\n\tID int `json:\"id\"`\n}\n"
  },
  {
    "path": "testdata/state/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/state/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @hostState admin petstore-admin.swagger.io\n// @hostState user petstore-user.swagger.io\n// @BasePath /v3\nfunc main() {\n\tstate := \"admin\" // \"admin\" or \"user\"\n\tswitch state {\n\tcase \"admin\":\n\t\thttp.HandleFunc(\"/admin/testapi/get-string-by-int/\", api.GetStringByInt)\n\t\thttp.HandleFunc(\"/admin/testapi/get-struct-array-by-string/\", api.GetStructArrayByString)\n\t\thttp.HandleFunc(\"/admin/testapi/upload\", api.Upload)\n\t\thttp.ListenAndServe(\":8080\", nil)\n\tcase \"user\":\n\t\thttp.HandleFunc(\"/testapi/get-string-by-int/\", api.GetStringByIntUser)\n\t\thttp.HandleFunc(\"/testapi/get-struct-array-by-string/\", api.GetStructArrayByStringUser)\n\t\thttp.HandleFunc(\"/testapi/upload\", api.UploadUser)\n\t\thttp.ListenAndServe(\":8080\", nil)\n\t}\n}\n"
  },
  {
    "path": "testdata/state/user_expected.json",
    "content": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a sample server Petstore server.\",\n        \"title\": \"Swagger Example API\",\n        \"termsOfService\": \"http://swagger.io/terms/\",\n        \"contact\": {\n            \"name\": \"API Support\",\n            \"url\": \"http://www.swagger.io/support\",\n            \"email\": \"support@swagger.io\"\n        },\n        \"license\": {\n            \"name\": \"Apache 2.0\",\n            \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n        },\n        \"version\": \"1.0\"\n    },\n    \"host\": \"petstore-user.swagger.io\",\n    \"basePath\": \"/v3\",\n    \"paths\": {\n        \"/file/upload\": {\n            \"post\": {\n                \"description\": \"Upload file\",\n                \"consumes\": [\n                    \"multipart/form-data\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Upload file\",\n                \"operationId\": \"file.upload\",\n                \"parameters\": [\n                    {\n                        \"type\": \"file\",\n                        \"description\": \"this is a test file\",\n                        \"name\": \"file\",\n                        \"in\": \"formData\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-string-by-int/{some_id}\": {\n            \"get\": {\n                \"description\": \"get string by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"summary\": \"Add a new pet to the store\",\n                \"operationId\": \"get-string-by-int\",\n                \"parameters\": [\n                    {\n                        \"type\": \"integer\",\n                        \"format\": \"int64\",\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    },\n                    {\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"body\",\n                        \"required\": true,\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.Pet\"\n                        }\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        },\n        \"/testapi/get-struct-array-by-string/{some_id}\": {\n            \"get\": {\n                \"security\": [\n                    {\n                        \"ApiKeyAuth\": []\n                    },\n                    {\n                        \"BasicAuth\": []\n                    },\n                    {\n                        \"OAuth2Application\": [\n                            \"write\"\n                        ]\n                    },\n                    {\n                        \"OAuth2Implicit\": [\n                            \"read\",\n                            \"admin\"\n                        ]\n                    },\n                    {\n                        \"OAuth2AccessCode\": [\n                            \"read\"\n                        ]\n                    },\n                    {\n                        \"OAuth2Password\": [\n                            \"admin\"\n                        ]\n                    }\n                ],\n                \"description\": \"get struct array by ID\",\n                \"consumes\": [\n                    \"application/json\"\n                ],\n                \"produces\": [\n                    \"application/json\"\n                ],\n                \"operationId\": \"get-struct-array-by-string\",\n                \"parameters\": [\n                    {\n                        \"type\": \"string\",\n                        \"description\": \"Some ID\",\n                        \"name\": \"some_id\",\n                        \"in\": \"path\",\n                        \"required\": true\n                    },\n                    {\n                        \"enum\": [\n                            1,\n                            2,\n                            3\n                        ],\n                        \"type\": \"integer\",\n                        \"description\": \"Category\",\n                        \"name\": \"category\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"minimum\": 0,\n                        \"type\": \"integer\",\n                        \"default\": 0,\n                        \"description\": \"Offset\",\n                        \"name\": \"offset\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"maximum\": 50,\n                        \"type\": \"integer\",\n                        \"default\": 10,\n                        \"description\": \"Limit\",\n                        \"name\": \"limit\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    },\n                    {\n                        \"maxLength\": 50,\n                        \"minLength\": 1,\n                        \"type\": \"string\",\n                        \"default\": \"\\\"\\\"\",\n                        \"description\": \"q\",\n                        \"name\": \"q\",\n                        \"in\": \"query\",\n                        \"required\": true\n                    }\n                ],\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"ok\",\n                        \"schema\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"400\": {\n                        \"description\": \"We need ID!!\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    },\n                    \"404\": {\n                        \"description\": \"Can not find ID\",\n                        \"schema\": {\n                            \"$ref\": \"#/definitions/web.APIError\"\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"definitions\": {\n        \"web.APIError\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"createdAt\": {\n                    \"type\": \"string\"\n                },\n                \"errorCode\": {\n                    \"type\": \"integer\"\n                },\n                \"errorMessage\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.Pet\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"category\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"id\": {\n                            \"type\": \"integer\",\n                            \"example\": 1\n                        },\n                        \"name\": {\n                            \"type\": \"string\",\n                            \"example\": \"category_name\"\n                        },\n                        \"photoURLs\": {\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"string\",\n                                \"format\": \"url\"\n                            },\n                            \"example\": [\n                                \"http://test/image/1.jpg\",\n                                \"http://test/image/2.jpg\"\n                            ]\n                        },\n                        \"smallCategory\": {\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"id\": {\n                                    \"type\": \"integer\",\n                                    \"example\": 1\n                                },\n                                \"name\": {\n                                    \"type\": \"string\",\n                                    \"example\": \"detail_category_name\"\n                                },\n                                \"photoURLs\": {\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"type\": \"string\"\n                                    },\n                                    \"example\": [\n                                        \"http://test/image/1.jpg\",\n                                        \"http://test/image/2.jpg\"\n                                    ]\n                                }\n                            }\n                        }\n                    }\n                },\n                \"data\": {},\n                \"decimal\": {\n                    \"type\": \"number\"\n                },\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\",\n                    \"example\": 1\n                },\n                \"isAlive\": {\n                    \"type\": \"boolean\",\n                    \"example\": true\n                },\n                \"name\": {\n                    \"type\": \"string\",\n                    \"example\": \"poti\"\n                },\n                \"pets\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet2\"\n                    }\n                },\n                \"pets2\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet2\"\n                    }\n                },\n                \"photoURLs\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    },\n                    \"example\": [\n                        \"http://test/image/1.jpg\",\n                        \"http://test/image/2.jpg\"\n                    ]\n                },\n                \"price\": {\n                    \"type\": \"number\",\n                    \"multipleOf\": 0.01,\n                    \"example\": 3.25\n                },\n                \"status\": {\n                    \"type\": \"string\"\n                },\n                \"tags\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Tag\"\n                    }\n                },\n                \"uuid\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.Pet2\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"deletedAt\": {\n                    \"type\": \"string\"\n                },\n                \"id\": {\n                    \"type\": \"integer\"\n                },\n                \"middleName\": {\n                    \"type\": \"string\"\n                }\n            }\n        },\n        \"web.RevValue\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"data\": {\n                    \"type\": \"integer\"\n                },\n                \"err\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int32\"\n                },\n                \"status\": {\n                    \"type\": \"boolean\"\n                }\n            }\n        },\n        \"web.Tag\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int64\"\n                },\n                \"name\": {\n                    \"type\": \"string\"\n                },\n                \"pets\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"$ref\": \"#/definitions/web.Pet\"\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/state/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n\n\tuuid \"github.com/gofrs/uuid\"\n\t\"github.com/shopspring/decimal\"\n)\n\ntype Pet struct {\n\tID       int `example:\"1\" format:\"int64\"`\n\tCategory struct {\n\t\tID            int      `example:\"1\"`\n\t\tName          string   `example:\"category_name\"`\n\t\tPhotoURLs     []string `example:\"http://test/image/1.jpg,http://test/image/2.jpg\" format:\"url\"`\n\t\tSmallCategory struct {\n\t\t\tID        int      `example:\"1\"`\n\t\t\tName      string   `example:\"detail_category_name\"`\n\t\t\tPhotoURLs []string `example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\t\t}\n\t}\n\tName      string   `example:\"poti\"`\n\tPhotoURLs []string `example:\"http://test/image/1.jpg,http://test/image/2.jpg\"`\n\tTags      []Tag\n\tPets      *[]Pet2\n\tPets2     []*Pet2\n\tStatus    string\n\tPrice     float32 `example:\"3.25\" multipleOf:\"0.01\"`\n\tIsAlive   bool    `example:\"true\"`\n\tData      interface{}\n\tHidden    string `json:\"-\"`\n\tUUID      uuid.UUID\n\tDecimal   decimal.Decimal\n\tFunction  func()\n}\n\ntype Tag struct {\n\tID   int `format:\"int64\"`\n\tName string\n\tPets []Pet\n}\n\ntype Pet2 struct {\n\tID         int\n\tMiddleName *string\n\tDeletedAt  *time.Time\n}\n\ntype APIError struct {\n\tErrorCode    int\n\tErrorMessage string\n\tCreatedAt    time.Time\n}\n\ntype RevValueBase struct {\n\tStatus bool\n\n\tErr int32\n}\ntype RevValue struct {\n\tRevValueBase\n\n\tData int\n}\n"
  },
  {
    "path": "testdata/struct_comment/api/api.go",
    "content": "package api\n\nimport \"net/http\"\n\n// @Summary Add a new pet to the store\n// @Description get string by ID\n// @Accept  json\n// @Produce  json\n// @Param   post_id      path   int     true  \"Some ID\" Format(int64)\n// @Success 200 {string} web.Post\n// @Failure 400 {object} web.APIError \"We need ID!!\"\n// @Failure 404 {object} web.APIError \"Can not find ID\"\n// @Router /posts/{post_id} [get]\nfunc GetPost(w http.ResponseWriter, r *http.Request) {\n\t//write your code\n}\n"
  },
  {
    "path": "testdata/struct_comment/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/swaggo/swag/testdata/struct_comment/api\"\n)\n\n// @title Swagger Example API\n// @version 1.0\n// @description This is a sample server Petstore server.\n// @host localhost:4000\n// @basePath /api\nfunc main() {\n\thttp.HandleFunc(\"/posts/\", api.GetPost)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "testdata/struct_comment/web/handler.go",
    "content": "package web\n\nimport (\n\t\"time\"\n)\n\ntype Post struct {\n\tID int `json:\"id\" example:\"1\" format:\"int64\"`\n\t// Post name\n\tName string `json:\"name\" example:\"poti\"`\n\t// Post data\n\tData struct {\n\t\t// Post tag\n\t\tTag []string `json:\"name\"`\n\t} `json:\"data\"`\n}\n\n// APIError\n// @Description API error\n// @Description with information about it\n// Other some summary\ntype APIError struct {\n\t// Error an Api error\n\tError string // Error this is Line comment\n\t// Error `number` tick comment\n\tErrorNo   int64\n\tErrorCtx  string    // Error `context` tick comment\n\tCreatedAt time.Time // Error time\n}\n"
  },
  {
    "path": "testdata/tags/apes.md",
    "content": "## Apes \n\nApes are very cool!"
  },
  {
    "path": "testdata/tags/api.md",
    "content": "## CoolApi Title\n\n### Cool API SubTitle\n\nWe love markdown!"
  },
  {
    "path": "testdata/tags/cats.md",
    "content": "## Cats \n\nCats are also very cool!"
  },
  {
    "path": "testdata/tags/main.go",
    "content": "package main\n\n// @description.markdown\n// @tag.name dogs\n// @tag.description Dogs are cool\n// @tag.name cats\n// @tag.description Cats are the devil\n// @tag.docs.url https://google.de\n// @tag.docs.description google is super useful to find out that cats are evil!\n// @tag.name apes\n// @tag.description Apes are also cool\nfunc main() {}\n"
  },
  {
    "path": "testdata/tags2/apes.md",
    "content": "## Apes \n\nApes are very cool!"
  },
  {
    "path": "testdata/tags2/api.md",
    "content": "## CoolApi Title\n\n### Cool API SubTitle\n\nWe love markdown!"
  },
  {
    "path": "testdata/tags2/main.go",
    "content": "package main\n\n// @description.markdown\n// @tag.name dogs\n// @tag.description Dogs are cool\n// @tag.name cats\n// @tag.description Cats are the devil\n// @tag.docs.url https://google.de\n// @tag.docs.description google is super useful to find out that cats are evil!\n// @tag.name apes\n// @tag.description.markdown\nfunc main() {}\n"
  },
  {
    "path": "testdata/tags_nonexistend_tag/apes.md",
    "content": "## Apes \n\nApes are very cool!"
  },
  {
    "path": "testdata/tags_nonexistend_tag/api.md",
    "content": "## CoolApi Title\n\n### Cool API SubTitle\n\nWe love markdown!"
  },
  {
    "path": "testdata/tags_nonexistend_tag/main.go",
    "content": "package main\n\n// @description.markdown\n// @tag.name dogs\n// @tag.description Dogs are cool\n// @tag.name cats\n// @tag.description Cats are the devil\n// @tag.docs.url https://google.de\n// @tag.docs.description google is super useful to find out that cats are evil!\n// @tag.description.markdown\nfunc main() {}\n"
  },
  {
    "path": "testdata/templated.go",
    "content": "package main\n\n// @termsOfService http://swagger.io/terms/\n\n// @contact.name API Support\n// @contact.url http://www.swagger.io/support\n// @contact.email support@swagger.io\n\n// @license.name Apache 2.0\n// @license.url http://www.apache.org/licenses/LICENSE-2.0.html\n\n// @securityDefinitions.basic BasicAuth\n\n// @securityDefinitions.apikey ApiKeyAuth\n// @in header\n// @name Authorization\n\n// @securitydefinitions.oauth2.application OAuth2Application\n// @tokenUrl https://example.com/oauth/token\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.implicit OAuth2Implicit\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.password OAuth2Password\n// @tokenUrl https://example.com/oauth/token\n// @scope.read Grants read access\n// @scope.write Grants write access\n// @scope.admin Grants read and write access to administrative information\n\n// @securitydefinitions.oauth2.accessCode OAuth2AccessCode\n// @tokenUrl https://example.com/oauth/token\n// @authorizationurl https://example.com/oauth/authorize\n// @scope.admin Grants read and write access to administrative information\n\n// @externalDocs.description OpenAPI\n// @externalDocs.url https://swagger.io/resources/open-api\n\n// @x-google-endpoints [{\"name\":\"name.endpoints.environment.cloud.goog\",\"allowCors\":true}]\n// @x-google-marks \"marks values\"\n\nfunc main() {}\n"
  },
  {
    "path": "testdata/users.md",
    "content": "Users Tag Markdown Description"
  },
  {
    "path": "types.go",
    "content": "package swag\n\nimport (\n\t\"go/ast\"\n\t\"go/token\"\n\t\"strings\"\n\n\t\"github.com/go-openapi/spec\"\n)\n\n// Schema parsed schema.\ntype Schema struct {\n\t*spec.Schema        //\n\tPkgPath      string // package import path used to rename Name of a definition int case of conflict\n\tName         string // Name in definitions\n}\n\n// TypeSpecDef the whole information of a typeSpec.\ntype TypeSpecDef struct {\n\t// ast file where TypeSpec is\n\tFile *ast.File\n\n\t// the TypeSpec of this type definition\n\tTypeSpec *ast.TypeSpec\n\n\tEnums []EnumValue\n\n\t// path of package starting from under ${GOPATH}/src or from module path in go.mod\n\tPkgPath    string\n\tParentSpec ast.Decl\n\n\tSchemaName string\n\n\tNotUnique bool\n}\n\n// Name the name of the typeSpec.\nfunc (t *TypeSpecDef) Name() string {\n\tif t.TypeSpec != nil && t.TypeSpec.Name != nil {\n\t\treturn t.TypeSpec.Name.Name\n\t}\n\n\treturn \"\"\n}\n\n// TypeName the type name of the typeSpec.\nfunc (t *TypeSpecDef) TypeName() string {\n\tif ignoreNameOverride(t.TypeSpec.Name.Name) {\n\t\treturn t.TypeSpec.Name.Name[1:]\n\t}\n\n\tvar names []string\n\tif t.NotUnique {\n\t\tpkgPath := strings.Map(func(r rune) rune {\n\t\t\tif r == '\\\\' || r == '/' || r == '.' {\n\t\t\t\treturn '_'\n\t\t\t}\n\t\t\treturn r\n\t\t}, t.PkgPath)\n\t\tnames = append(names, pkgPath)\n\t} else if t.File != nil {\n\t\tnames = append(names, t.File.Name.Name)\n\t}\n\tif parentFun, ok := (t.ParentSpec).(*ast.FuncDecl); ok && parentFun != nil {\n\t\tnames = append(names, parentFun.Name.Name)\n\t}\n\tnames = append(names, t.TypeSpec.Name.Name)\n\treturn fullTypeName(names...)\n}\n\n// FullPath return the full path of the typeSpec.\nfunc (t *TypeSpecDef) FullPath() string {\n\treturn t.PkgPath + \".\" + t.Name()\n}\n\nfunc (t *TypeSpecDef) Alias() string {\n\treturn nameOverride(t.TypeSpec.Comment)\n}\n\nfunc (t *TypeSpecDef) SetSchemaName() {\n\tif alias := t.Alias(); alias != \"\" {\n\t\tt.SchemaName = alias\n\t\treturn\n\t}\n\n\tt.SchemaName = t.TypeName()\n}\n\n// AstFileInfo information of an ast.File.\ntype AstFileInfo struct {\n\t//FileSet the FileSet object which is used to parse this go source file\n\tFileSet *token.FileSet\n\n\t// File ast.File\n\tFile *ast.File\n\n\t// Path the path of the ast.File\n\tPath string\n\n\t// PackagePath package import path of the ast.File\n\tPackagePath string\n\n\t// ParseFlag determine what to parse\n\tParseFlag ParseFlag\n}\n"
  },
  {
    "path": "utils.go",
    "content": "package swag\n\nimport (\n\t\"strings\"\n\t\"unicode\"\n)\n\n// FieldsFunc split a string s by a func splitter into max n parts\nfunc FieldsFunc(s string, f func(rune2 rune) bool, n int) []string {\n\t// A span is used to record a slice of s of the form s[start:end].\n\t// The start index is inclusive and the end index is exclusive.\n\ttype span struct {\n\t\tstart int\n\t\tend   int\n\t}\n\tspans := make([]span, 0, 32)\n\n\t// Find the field start and end indices.\n\t// Doing this in a separate pass (rather than slicing the string s\n\t// and collecting the result substrings right away) is significantly\n\t// more efficient, possibly due to cache effects.\n\tstart := -1 // valid span start if >= 0\n\tfor end, rune := range s {\n\t\tif f(rune) {\n\t\t\tif start >= 0 {\n\t\t\t\tspans = append(spans, span{start, end})\n\t\t\t\t// Set start to a negative value.\n\t\t\t\t// Note: using -1 here consistently and reproducibly\n\t\t\t\t// slows down this code by a several percent on amd64.\n\t\t\t\tstart = ^start\n\t\t\t}\n\t\t} else {\n\t\t\tif start < 0 {\n\t\t\t\tstart = end\n\t\t\t\tif n > 0 && len(spans)+1 >= n {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Last field might end at EOF.\n\tif start >= 0 {\n\t\tspans = append(spans, span{start, len(s)})\n\t}\n\n\t// Create strings from recorded field indices.\n\ta := make([]string, len(spans))\n\tfor i, span := range spans {\n\t\ta[i] = s[span.start:span.end]\n\t}\n\treturn a\n}\n\n// FieldsByAnySpace split a string s by any space character into max n parts\nfunc FieldsByAnySpace(s string, n int) []string {\n\treturn FieldsFunc(s, unicode.IsSpace, n)\n}\n\n// AppendDescription appends a new string to the existing description, treating\n// a trailing backslash as a line continuation.\nfunc AppendDescription(current, addition string) string {\n\tif strings.HasSuffix(current, \"\\\\\") {\n\t\treturn current[:len(current)-1] + addition\n\t}\n\treturn current + \"\\n\" + addition\n}\n"
  },
  {
    "path": "utils_test.go",
    "content": "package swag\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFieldsByAnySpace(t *testing.T) {\n\ttype args struct {\n\t\ts string\n\t\tn int\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant []string\n\t}{\n\t\t{\"test1\",\n\t\t\targs{\n\t\t\t\t\"\taa\tbb\tcc dd \t\tff\",\n\t\t\t\t2,\n\t\t\t},\n\t\t\t[]string{\"aa\", \"bb\\tcc dd \\t\\tff\"},\n\t\t},\n\t\t{\"test2\",\n\t\t\targs{\n\t\t\t\t`\taa\t\"bb\tcc dd \t\tff\"`,\n\t\t\t\t2,\n\t\t\t},\n\t\t\t[]string{\"aa\", `\"bb\tcc dd \t\tff\"`},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tassert.Equalf(t, tt.want, FieldsByAnySpace(tt.args.s, tt.args.n), \"FieldsByAnySpace(%v,  %v)\", tt.args.s, tt.args.n)\n\t\t})\n\t}\n}\n\nfunc TestAppendDescription(t *testing.T) {\n\ttype args struct {\n\t\tcurrent  string\n\t\taddition string\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant string\n\t}{\n\t\t{\"test1\",\n\t\t\targs{\n\t\t\t\t\"aa\",\n\t\t\t\t\"bb\",\n\t\t\t},\n\t\t\t\"aa\\nbb\",\n\t\t},\n\t\t{\"test2\",\n\t\t\targs{\n\t\t\t\t\"aa\\\\\",\n\t\t\t\t\"bb\",\n\t\t\t},\n\t\t\t\"aabb\",\n\t\t},\n\t\t{\"test3\",\n\t\t\targs{\n\t\t\t\t\"aa \\\\\",\n\t\t\t\t\"bb\",\n\t\t\t},\n\t\t\t\"aa bb\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tassert.Equalf(t, tt.want, AppendDescription(tt.args.current, tt.args.addition), \"AppendDescription(%v,  %v)\", tt.args.current, tt.args.addition)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "version.go",
    "content": "package swag\n\n// Version of swag.\nconst Version = \"v1.16.7\"\n"
  }
]