forked from ebhomengo/niki
feat(niki): add swagger not completed
This commit is contained in:
parent
28ee6babd3
commit
b039bfcb95
|
@ -0,0 +1,2 @@
|
||||||
|
NIKI_STAGE_MARIADB_UR_PASSWORD="nikiappt0lk2o20"
|
||||||
|
NIKI_STAGE_MARIADB_RT_PASSWORD="nikiappt0lk2o20"
|
|
@ -20,7 +20,7 @@
|
||||||
.idea
|
.idea
|
||||||
bin
|
bin
|
||||||
|
|
||||||
#env
|
#.env
|
||||||
*.env
|
*.env
|
||||||
|
|
||||||
logs/
|
logs/
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[env]
|
[env]
|
||||||
# supports arbitrary env vars so rtx can be used like direnv/dotenv
|
# supports arbitrary .env vars so rtx can be used like direnv/dotenv
|
||||||
GO_ENV = 'GOLANG_MISE'
|
GO_ENV = 'GOLANG_MISE'
|
||||||
MISE_USE_TOML= 1 #Set to 1 to default to using .mise.toml
|
MISE_USE_TOML= 1 #Set to 1 to default to using .mise.toml
|
||||||
RUST_BACKTRACE=0
|
RUST_BACKTRACE=0
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -18,4 +18,10 @@ format:
|
||||||
@golangci-lint run --fix
|
@golangci-lint run --fix
|
||||||
|
|
||||||
build:
|
build:
|
||||||
go build main.go
|
go build main.go --migrate
|
||||||
|
|
||||||
|
run:
|
||||||
|
go run main.go --migrate
|
||||||
|
|
||||||
|
docker:
|
||||||
|
sudo docker compose up -d
|
|
@ -29,7 +29,7 @@ type Option struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// our environment variables must prefix with `EB_`
|
// our environment variables must prefix with `EB_`
|
||||||
// for nested env should use `__` aka: EB__DB__HOST.
|
// for nested .env should use `__` aka: EB__DB__HOST.
|
||||||
func defaultCallbackEnv(source string) string {
|
func defaultCallbackEnv(source string) string {
|
||||||
base := strings.ToLower(strings.TrimPrefix(source, defaultPrefix))
|
base := strings.ToLower(strings.TrimPrefix(source, defaultPrefix))
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,16 @@ import (
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AddAddress godoc
|
||||||
|
// @Summary Add Address benefactor
|
||||||
|
// @Tags benefactor
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param Request body param.BenefactorAddAddressRequest true "Add Address benefactor"
|
||||||
|
// @Success 200 {object} param.BenefactorAddAddressResponse
|
||||||
|
// @Failure 400 {string} "Bad request"
|
||||||
|
// @Router /address/ [post]
|
||||||
|
// @Security AuthBearer
|
||||||
func (h Handler) AddAddress(c echo.Context) error {
|
func (h Handler) AddAddress(c echo.Context) error {
|
||||||
req := param.BenefactorAddAddressRequest{}
|
req := param.BenefactorAddAddressRequest{}
|
||||||
if bErr := c.Bind(&req); bErr != nil {
|
if bErr := c.Bind(&req); bErr != nil {
|
||||||
|
|
|
@ -8,6 +8,14 @@ import (
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GetAllCities godoc
|
||||||
|
// @Summary get all cities
|
||||||
|
// @Tags benefactor
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} addressparam.GetAllCitiesResponse
|
||||||
|
// @Failure 400 {string} "Bad request"
|
||||||
|
// @Router /address/cities [get]
|
||||||
func (h Handler) GetAllCities(c echo.Context) error {
|
func (h Handler) GetAllCities(c echo.Context) error {
|
||||||
var req addressparam.GetAllCitiesRequest
|
var req addressparam.GetAllCitiesRequest
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,14 @@ import (
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GetAllProvinces godoc
|
||||||
|
// @Summary get all provinces
|
||||||
|
// @Tags benefactor
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} addressparam.GetAllProvincesResponse
|
||||||
|
// @Failure 400 {string} "Bad request"
|
||||||
|
// @Router /address/provinces [get]
|
||||||
func (h Handler) GetAllProvinces(c echo.Context) error {
|
func (h Handler) GetAllProvinces(c echo.Context) error {
|
||||||
var req addressparam.GetAllProvincesRequest
|
var req addressparam.GetAllProvincesRequest
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,15 @@ import (
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// loginOrRegister godoc
|
||||||
|
// @Summary login Or Register benefactor
|
||||||
|
// @Tags benefactor
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param Request body benefactoreparam.LoginOrRegisterRequest true "login Or Register benefactor"
|
||||||
|
// @Success 200 {object} benefactoreparam.LoginOrRegisterResponse
|
||||||
|
// @Failure 400 {string} "Bad request"
|
||||||
|
// @Router /benefactor/login-register [post]
|
||||||
func (h Handler) loginOrRegister(c echo.Context) error {
|
func (h Handler) loginOrRegister(c echo.Context) error {
|
||||||
var req benefactoreparam.LoginOrRegisterRequest
|
var req benefactoreparam.LoginOrRegisterRequest
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,15 @@ import (
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SendOtp godoc
|
||||||
|
// @Summary send otp benefactor
|
||||||
|
// @Tags benefactor
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param Request body benefactoreparam.SendOtpRequest true "send otp benefactor"
|
||||||
|
// @Success 200 {object} benefactoreparam.SendOtpResponse
|
||||||
|
// @Failure 400 {string} "Bad request"
|
||||||
|
// @Router /benefactor/send-otp [post]
|
||||||
func (h Handler) SendOtp(c echo.Context) error {
|
func (h Handler) SendOtp(c echo.Context) error {
|
||||||
var req benefactoreparam.SendOtpRequest
|
var req benefactoreparam.SendOtpRequest
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,13 @@ package httpserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
config "git.gocasts.ir/ebhomengo/niki/config"
|
config "git.gocasts.ir/ebhomengo/niki/config"
|
||||||
adminhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/admin/admin"
|
adminhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/admin/admin"
|
||||||
adminkindboxreqhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/admin/kind_box_req"
|
adminkindboxreqhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/admin/kind_box_req"
|
||||||
benefactoraddresshandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/address"
|
benefactoraddresshandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/address"
|
||||||
benefactorhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/benefactor"
|
benefactorhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/benefactor"
|
||||||
benefactorkindboxreqhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/kind_box_req"
|
benefactorkindboxreqhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/kind_box_req"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/docs"
|
||||||
adminservice "git.gocasts.ir/ebhomengo/niki/service/admin/admin"
|
adminservice "git.gocasts.ir/ebhomengo/niki/service/admin/admin"
|
||||||
adminauthorizationservice "git.gocasts.ir/ebhomengo/niki/service/admin/authorization"
|
adminauthorizationservice "git.gocasts.ir/ebhomengo/niki/service/admin/authorization"
|
||||||
adminkindboxreqservice "git.gocasts.ir/ebhomengo/niki/service/admin/kind_box_req"
|
adminkindboxreqservice "git.gocasts.ir/ebhomengo/niki/service/admin/kind_box_req"
|
||||||
|
@ -23,6 +23,7 @@ import (
|
||||||
benefactorkindboxreqvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/kind_box_req"
|
benefactorkindboxreqvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/kind_box_req"
|
||||||
echo "github.com/labstack/echo/v4"
|
echo "github.com/labstack/echo/v4"
|
||||||
middleware "github.com/labstack/echo/v4/middleware"
|
middleware "github.com/labstack/echo/v4/middleware"
|
||||||
|
echoSwagger "github.com/swaggo/echo-swagger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
@ -64,8 +65,8 @@ func New(
|
||||||
|
|
||||||
func (s Server) Serve() {
|
func (s Server) Serve() {
|
||||||
s.Router.Use(middleware.RequestID())
|
s.Router.Use(middleware.RequestID())
|
||||||
|
|
||||||
s.Router.Use(middleware.Recover())
|
s.Router.Use(middleware.Recover())
|
||||||
|
RegisterSwagger(s.Router, s.config)
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
s.Router.GET("/health-check", s.healthCheck)
|
s.Router.GET("/health-check", s.healthCheck)
|
||||||
|
@ -74,7 +75,6 @@ func (s Server) Serve() {
|
||||||
s.benefactorAddressHandler.SetRoutes(s.Router)
|
s.benefactorAddressHandler.SetRoutes(s.Router)
|
||||||
s.adminHandler.SetRoutes(s.Router)
|
s.adminHandler.SetRoutes(s.Router)
|
||||||
s.adminKindBoxReqHandler.SetRoutes(s.Router)
|
s.adminKindBoxReqHandler.SetRoutes(s.Router)
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
address := fmt.Sprintf(":%d", s.config.HTTPServer.Port)
|
address := fmt.Sprintf(":%d", s.config.HTTPServer.Port)
|
||||||
fmt.Printf("start echo server on %s\n", address)
|
fmt.Printf("start echo server on %s\n", address)
|
||||||
|
@ -82,3 +82,12 @@ func (s Server) Serve() {
|
||||||
fmt.Println("router start error", err)
|
fmt.Println("router start error", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RegisterSwagger(s *echo.Echo, config config.Config) {
|
||||||
|
docs.SwaggerInfo.Title = "NIKI Api"
|
||||||
|
docs.SwaggerInfo.Description = " This is swagger api documentation for niki project"
|
||||||
|
docs.SwaggerInfo.Version = "1.0.0"
|
||||||
|
//docs.SwaggerInfo.BasePath = "/api"
|
||||||
|
docs.SwaggerInfo.Host = fmt.Sprintf("localhost:%d", config.HTTPServer.Port)
|
||||||
|
s.GET("/swagger/*any", echoSwagger.WrapHandler)
|
||||||
|
}
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
version: '3.9'
|
version: '3.9'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
niki-core:
|
# niki-core:
|
||||||
build:
|
# build:
|
||||||
context: .
|
# context: .
|
||||||
target: development
|
# target: development
|
||||||
image: niki-core
|
# image: niki-core
|
||||||
container_name: niki-core
|
# container_name: niki-core
|
||||||
networks:
|
# networks:
|
||||||
- core
|
# - core
|
||||||
restart: always
|
# restart: always
|
||||||
ports:
|
# ports:
|
||||||
- "1313:1313"
|
# - "1313:1313"
|
||||||
links:
|
# links:
|
||||||
- "niki-mariadb"
|
# - "niki-mariadb"
|
||||||
depends_on:
|
# depends_on:
|
||||||
- "niki-mariadb"
|
# - "niki-mariadb"
|
||||||
- "niki-redis"
|
# - "niki-redis"
|
||||||
|
|
||||||
niki-mariadb:
|
niki-mariadb:
|
||||||
image: docker.io/bitnami/mariadb:11.1
|
image: docker.io/bitnami/mariadb:11.1
|
||||||
|
|
|
@ -0,0 +1,422 @@
|
||||||
|
// Package docs Code generated by swaggo/swag. DO NOT EDIT
|
||||||
|
package docs
|
||||||
|
|
||||||
|
import "github.com/swaggo/swag"
|
||||||
|
|
||||||
|
const docTemplate = `{
|
||||||
|
"schemes": {{ marshal .Schemes }},
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"description": "{{escape .Description}}",
|
||||||
|
"title": "{{.Title}}",
|
||||||
|
"contact": {},
|
||||||
|
"version": "{{.Version}}"
|
||||||
|
},
|
||||||
|
"host": "{{.Host}}",
|
||||||
|
"basePath": "{{.BasePath}}",
|
||||||
|
"paths": {
|
||||||
|
"/address/": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"AuthBearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"benefactor"
|
||||||
|
],
|
||||||
|
"summary": "Add Address benefactor",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Add Address benefactor",
|
||||||
|
"name": "Request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/addressparam.BenefactorAddAddressRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/addressparam.BenefactorAddAddressResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/address/cities": {
|
||||||
|
"get": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"benefactor"
|
||||||
|
],
|
||||||
|
"summary": "get all cities",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/addressparam.GetAllCitiesResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/address/provinces": {
|
||||||
|
"get": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"benefactor"
|
||||||
|
],
|
||||||
|
"summary": "get all provinces",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/addressparam.GetAllProvincesResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/benefactor/login-register": {
|
||||||
|
"post": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"benefactor"
|
||||||
|
],
|
||||||
|
"summary": "login Or Register benefactor",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "login Or Register benefactor",
|
||||||
|
"name": "Request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.LoginOrRegisterRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.LoginOrRegisterResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/benefactor/send-otp": {
|
||||||
|
"post": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"benefactor"
|
||||||
|
],
|
||||||
|
"summary": "send otp benefactor",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "send otp benefactor",
|
||||||
|
"name": "Request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.SendOtpRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.SendOtpResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"addressparam.BenefactorAddAddressRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"address": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "tehran"
|
||||||
|
},
|
||||||
|
"benefactor_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
},
|
||||||
|
"city_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
},
|
||||||
|
"lat": {
|
||||||
|
"type": "number",
|
||||||
|
"example": 22.23
|
||||||
|
},
|
||||||
|
"lon": {
|
||||||
|
"type": "number",
|
||||||
|
"example": 22.22
|
||||||
|
},
|
||||||
|
"postal_code": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1234567890"
|
||||||
|
},
|
||||||
|
"province_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"addressparam.BenefactorAddAddressResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"address": {
|
||||||
|
"$ref": "#/definitions/entity.Address"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"addressparam.GetAllCitiesResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"cities": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/entity.City"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"addressparam.GetAllProvincesResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"provinces": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/entity.Province"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.BenefactroInfo": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"first_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "mehdi"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
},
|
||||||
|
"last_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "rez"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "benefactor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.LoginOrRegisterRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"phone_number": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "09198829528"
|
||||||
|
},
|
||||||
|
"verification_code": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "123456"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.LoginOrRegisterResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"benefactore_info": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.BenefactroInfo"
|
||||||
|
},
|
||||||
|
"tokens": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.Tokens"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.SendOtpRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"phone_number": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "09198829528"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.SendOtpResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"description": "this just use in test .env\n\t\tTODO - remove it after test",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"phone_number": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "09198829528"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.Tokens": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"access_token": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"refresh_token": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entity.Address": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"address": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"benefactorID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"cityID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"isMain": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"lat": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"lon": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"postalCode": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"provinceID": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entity.City": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"provinceID": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entity.Province": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"securityDefinitions": {
|
||||||
|
"AuthBearer": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||||
|
var SwaggerInfo = &swag.Spec{
|
||||||
|
Version: "",
|
||||||
|
Host: "",
|
||||||
|
BasePath: "",
|
||||||
|
Schemes: []string{},
|
||||||
|
Title: "",
|
||||||
|
Description: "",
|
||||||
|
InfoInstanceName: "swagger",
|
||||||
|
SwaggerTemplate: docTemplate,
|
||||||
|
LeftDelim: "{{",
|
||||||
|
RightDelim: "}}",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
||||||
|
}
|
|
@ -0,0 +1,393 @@
|
||||||
|
{
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"contact": {}
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"/address/": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"AuthBearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"benefactor"
|
||||||
|
],
|
||||||
|
"summary": "Add Address benefactor",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Add Address benefactor",
|
||||||
|
"name": "Request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/addressparam.BenefactorAddAddressRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/addressparam.BenefactorAddAddressResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/address/cities": {
|
||||||
|
"get": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"benefactor"
|
||||||
|
],
|
||||||
|
"summary": "get all cities",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/addressparam.GetAllCitiesResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/address/provinces": {
|
||||||
|
"get": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"benefactor"
|
||||||
|
],
|
||||||
|
"summary": "get all provinces",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/addressparam.GetAllProvincesResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/benefactor/login-register": {
|
||||||
|
"post": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"benefactor"
|
||||||
|
],
|
||||||
|
"summary": "login Or Register benefactor",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "login Or Register benefactor",
|
||||||
|
"name": "Request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.LoginOrRegisterRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.LoginOrRegisterResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/benefactor/send-otp": {
|
||||||
|
"post": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"benefactor"
|
||||||
|
],
|
||||||
|
"summary": "send otp benefactor",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "send otp benefactor",
|
||||||
|
"name": "Request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.SendOtpRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.SendOtpResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"addressparam.BenefactorAddAddressRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"address": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "tehran"
|
||||||
|
},
|
||||||
|
"benefactor_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
},
|
||||||
|
"city_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
},
|
||||||
|
"lat": {
|
||||||
|
"type": "number",
|
||||||
|
"example": 22.23
|
||||||
|
},
|
||||||
|
"lon": {
|
||||||
|
"type": "number",
|
||||||
|
"example": 22.22
|
||||||
|
},
|
||||||
|
"postal_code": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1234567890"
|
||||||
|
},
|
||||||
|
"province_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"addressparam.BenefactorAddAddressResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"address": {
|
||||||
|
"$ref": "#/definitions/entity.Address"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"addressparam.GetAllCitiesResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"cities": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/entity.City"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"addressparam.GetAllProvincesResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"provinces": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/entity.Province"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.BenefactroInfo": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"first_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "mehdi"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
},
|
||||||
|
"last_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "rez"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "benefactor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.LoginOrRegisterRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"phone_number": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "09198829528"
|
||||||
|
},
|
||||||
|
"verification_code": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "123456"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.LoginOrRegisterResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"benefactore_info": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.BenefactroInfo"
|
||||||
|
},
|
||||||
|
"tokens": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.Tokens"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.SendOtpRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"phone_number": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "09198829528"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.SendOtpResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"description": "this just use in test .env\n\t\tTODO - remove it after test",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"phone_number": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "09198829528"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.Tokens": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"access_token": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"refresh_token": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entity.Address": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"address": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"benefactorID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"cityID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"isMain": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"lat": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"lon": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"postalCode": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"provinceID": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entity.City": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"provinceID": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entity.Province": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"securityDefinitions": {
|
||||||
|
"AuthBearer": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,256 @@
|
||||||
|
definitions:
|
||||||
|
addressparam.BenefactorAddAddressRequest:
|
||||||
|
properties:
|
||||||
|
address:
|
||||||
|
example: tehran
|
||||||
|
type: string
|
||||||
|
benefactor_id:
|
||||||
|
example: 1
|
||||||
|
type: integer
|
||||||
|
city_id:
|
||||||
|
example: 1
|
||||||
|
type: integer
|
||||||
|
lat:
|
||||||
|
example: 22.23
|
||||||
|
type: number
|
||||||
|
lon:
|
||||||
|
example: 22.22
|
||||||
|
type: number
|
||||||
|
postal_code:
|
||||||
|
example: "1234567890"
|
||||||
|
type: string
|
||||||
|
province_id:
|
||||||
|
example: 1
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
addressparam.BenefactorAddAddressResponse:
|
||||||
|
properties:
|
||||||
|
address:
|
||||||
|
$ref: '#/definitions/entity.Address'
|
||||||
|
type: object
|
||||||
|
addressparam.GetAllCitiesResponse:
|
||||||
|
properties:
|
||||||
|
cities:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/entity.City'
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
addressparam.GetAllProvincesResponse:
|
||||||
|
properties:
|
||||||
|
provinces:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/entity.Province'
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
benefactoreparam.BenefactroInfo:
|
||||||
|
properties:
|
||||||
|
first_name:
|
||||||
|
example: mehdi
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
example: 1
|
||||||
|
type: integer
|
||||||
|
last_name:
|
||||||
|
example: rez
|
||||||
|
type: string
|
||||||
|
role:
|
||||||
|
example: benefactor
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
benefactoreparam.LoginOrRegisterRequest:
|
||||||
|
properties:
|
||||||
|
phone_number:
|
||||||
|
example: "09198829528"
|
||||||
|
type: string
|
||||||
|
verification_code:
|
||||||
|
example: "123456"
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
benefactoreparam.LoginOrRegisterResponse:
|
||||||
|
properties:
|
||||||
|
benefactore_info:
|
||||||
|
$ref: '#/definitions/benefactoreparam.BenefactroInfo'
|
||||||
|
tokens:
|
||||||
|
$ref: '#/definitions/benefactoreparam.Tokens'
|
||||||
|
type: object
|
||||||
|
benefactoreparam.SendOtpRequest:
|
||||||
|
properties:
|
||||||
|
phone_number:
|
||||||
|
example: "09198829528"
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
benefactoreparam.SendOtpResponse:
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
description: "this just use in test .env\n\t\tTODO - remove it after test"
|
||||||
|
type: string
|
||||||
|
phone_number:
|
||||||
|
example: "09198829528"
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
benefactoreparam.Tokens:
|
||||||
|
properties:
|
||||||
|
access_token:
|
||||||
|
type: string
|
||||||
|
refresh_token:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
entity.Address:
|
||||||
|
properties:
|
||||||
|
address:
|
||||||
|
type: string
|
||||||
|
benefactorID:
|
||||||
|
type: integer
|
||||||
|
cityID:
|
||||||
|
type: integer
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
isMain:
|
||||||
|
type: boolean
|
||||||
|
lat:
|
||||||
|
type: number
|
||||||
|
lon:
|
||||||
|
type: number
|
||||||
|
postalCode:
|
||||||
|
type: string
|
||||||
|
provinceID:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
entity.City:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
provinceID:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
entity.Province:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
info:
|
||||||
|
contact: {}
|
||||||
|
paths:
|
||||||
|
/address/:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Add Address benefactor
|
||||||
|
in: body
|
||||||
|
name: Request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/addressparam.BenefactorAddAddressRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/addressparam.BenefactorAddAddressResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
security:
|
||||||
|
- AuthBearer: []
|
||||||
|
summary: Add Address benefactor
|
||||||
|
tags:
|
||||||
|
- benefactor
|
||||||
|
/address/cities:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/addressparam.GetAllCitiesResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
summary: get all cities
|
||||||
|
tags:
|
||||||
|
- benefactor
|
||||||
|
/address/provinces:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/addressparam.GetAllProvincesResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
summary: get all provinces
|
||||||
|
tags:
|
||||||
|
- benefactor
|
||||||
|
/benefactor/login-register:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: login Or Register benefactor
|
||||||
|
in: body
|
||||||
|
name: Request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/benefactoreparam.LoginOrRegisterRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/benefactoreparam.LoginOrRegisterResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
summary: login Or Register benefactor
|
||||||
|
tags:
|
||||||
|
- benefactor
|
||||||
|
/benefactor/send-otp:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: send otp benefactor
|
||||||
|
in: body
|
||||||
|
name: Request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/benefactoreparam.SendOtpRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/benefactoreparam.SendOtpResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
summary: send otp benefactor
|
||||||
|
tags:
|
||||||
|
- benefactor
|
||||||
|
securityDefinitions:
|
||||||
|
AuthBearer:
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
|
type: apiKey
|
||||||
|
swagger: "2.0"
|
25
go.mod
25
go.mod
|
@ -11,36 +11,49 @@ require (
|
||||||
github.com/kavenegar/kavenegar-go v0.0.0-20221124112814-40341057b5ca
|
github.com/kavenegar/kavenegar-go v0.0.0-20221124112814-40341057b5ca
|
||||||
github.com/knadh/koanf v1.5.0
|
github.com/knadh/koanf v1.5.0
|
||||||
github.com/labstack/echo-jwt/v4 v4.2.0
|
github.com/labstack/echo-jwt/v4 v4.2.0
|
||||||
github.com/labstack/echo/v4 v4.11.4
|
github.com/labstack/echo/v4 v4.12.0
|
||||||
github.com/redis/go-redis/v9 v9.4.0
|
github.com/redis/go-redis/v9 v9.4.0
|
||||||
github.com/rubenv/sql-migrate v1.6.0
|
github.com/rubenv/sql-migrate v1.6.0
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.9.0
|
||||||
golang.org/x/crypto v0.17.0
|
github.com/swaggo/echo-swagger v1.4.1
|
||||||
|
golang.org/x/crypto v0.23.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 // indirect
|
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/fatih/structs v1.1.0 // indirect
|
github.com/fatih/structs v1.1.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
|
github.com/ghodss/yaml v1.0.0 // indirect
|
||||||
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/spec v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect
|
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect
|
||||||
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/labstack/gommon v0.4.2 // indirect
|
github.com/labstack/gommon v0.4.2 // indirect
|
||||||
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/swaggo/files/v2 v2.0.0 // indirect
|
||||||
|
github.com/swaggo/swag v1.16.3 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
golang.org/x/net v0.19.0 // indirect
|
golang.org/x/net v0.25.0 // indirect
|
||||||
golang.org/x/sys v0.15.0 // indirect
|
golang.org/x/sys v0.20.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.15.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
|
golang.org/x/tools v0.21.0 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
56
go.sum
56
go.sum
|
@ -1,6 +1,8 @@
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||||
|
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
@ -60,6 +62,7 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
|
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
|
||||||
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
|
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
|
||||||
|
@ -70,6 +73,14 @@ github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||||
|
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
||||||
|
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||||
|
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||||
|
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE=
|
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE=
|
||||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
|
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
|
||||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
|
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
|
||||||
|
@ -158,6 +169,8 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||||
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
@ -183,12 +196,14 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/labstack/echo-jwt/v4 v4.2.0 h1:odSISV9JgcSCuhgQSV/6Io3i7nUmfM/QkBeR5GVJj5c=
|
github.com/labstack/echo-jwt/v4 v4.2.0 h1:odSISV9JgcSCuhgQSV/6Io3i7nUmfM/QkBeR5GVJj5c=
|
||||||
github.com/labstack/echo-jwt/v4 v4.2.0/go.mod h1:MA2RqdXdEn4/uEglx0HcUOgQSyBaTh5JcaHIan3biwU=
|
github.com/labstack/echo-jwt/v4 v4.2.0/go.mod h1:MA2RqdXdEn4/uEglx0HcUOgQSyBaTh5JcaHIan3biwU=
|
||||||
github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8=
|
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
|
||||||
github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8=
|
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
|
||||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||||
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
||||||
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
@ -264,8 +279,8 @@ github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwy
|
||||||
github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||||
github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
|
github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
github.com/rubenv/sql-migrate v1.6.0 h1:IZpcTlAx/VKXphWEpwWJ7BaMq05tYtE80zYz+8a5Il8=
|
github.com/rubenv/sql-migrate v1.6.0 h1:IZpcTlAx/VKXphWEpwWJ7BaMq05tYtE80zYz+8a5Il8=
|
||||||
github.com/rubenv/sql-migrate v1.6.0/go.mod h1:m3ilnKP7sNb4eYkLsp6cGdPOl4OBcXM6rcbzU+Oqc5k=
|
github.com/rubenv/sql-migrate v1.6.0/go.mod h1:m3ilnKP7sNb4eYkLsp6cGdPOl4OBcXM6rcbzU+Oqc5k=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
|
@ -284,8 +299,14 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/swaggo/echo-swagger v1.4.1 h1:Yf0uPaJWp1uRtDloZALyLnvdBeoEL5Kc7DtnjzO/TUk=
|
||||||
|
github.com/swaggo/echo-swagger v1.4.1/go.mod h1:C8bSi+9yH2FLZsnhqMZLIZddpUxZdBYuNHbtaS1Hljc=
|
||||||
|
github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw=
|
||||||
|
github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM=
|
||||||
|
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
|
||||||
|
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
|
@ -304,8 +325,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
@ -315,6 +336,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||||
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
@ -332,8 +355,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -346,6 +369,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
@ -378,8 +403,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
@ -387,8 +412,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
|
@ -403,6 +428,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
|
||||||
|
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -450,6 +477,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
3
main.go
3
main.go
|
@ -26,6 +26,9 @@ func parseFlags() bool {
|
||||||
return *migrateFlag
|
return *migrateFlag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @securityDefinitions.apikey AuthBearer
|
||||||
|
// @in header
|
||||||
|
// @name Authorization
|
||||||
func main() {
|
func main() {
|
||||||
migrate := parseFlags()
|
migrate := parseFlags()
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,13 @@ package addressparam
|
||||||
import "git.gocasts.ir/ebhomengo/niki/entity"
|
import "git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
|
||||||
type BenefactorAddAddressRequest struct {
|
type BenefactorAddAddressRequest struct {
|
||||||
PostalCode string `json:"postal_code"`
|
PostalCode string `json:"postal_code" example:"1234567890"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address" example:"tehran"`
|
||||||
Lat float64 `json:"lat"`
|
Lat float64 `json:"lat" example:"22.23"`
|
||||||
Lon float64 `json:"lon"`
|
Lon float64 `json:"lon" example:"22.22"`
|
||||||
CityID uint `json:"city_id"`
|
CityID uint `json:"city_id" example:"1"`
|
||||||
ProvinceID uint `json:"province_id"`
|
ProvinceID uint `json:"province_id" example:"1"`
|
||||||
BenefactorID uint `json:"benefactor_id"`
|
BenefactorID uint `json:"benefactor_id" example:"1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BenefactorAddAddressResponse struct {
|
type BenefactorAddAddressResponse struct {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package benefactoreparam
|
package benefactoreparam
|
||||||
|
|
||||||
type BenefactroInfo struct {
|
type BenefactroInfo struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id" example:"1"`
|
||||||
FirstName string `json:"first_name"`
|
FirstName string `json:"first_name" example:"mehdi"`
|
||||||
LastName string `json:"last_name"`
|
LastName string `json:"last_name" example:"rez"`
|
||||||
Role string `json:"role"`
|
Role string `json:"role" example:"benefactor"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package benefactoreparam
|
package benefactoreparam
|
||||||
|
|
||||||
type LoginOrRegisterRequest struct {
|
type LoginOrRegisterRequest struct {
|
||||||
PhoneNumber string `json:"phone_number"`
|
PhoneNumber string `json:"phone_number" example:"09198829528"`
|
||||||
VerificationCode string `json:"verification_code"`
|
VerificationCode string `json:"verification_code" example:"123456"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoginOrRegisterResponse struct {
|
type LoginOrRegisterResponse struct {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package benefactoreparam
|
package benefactoreparam
|
||||||
|
|
||||||
type SendOtpRequest struct {
|
type SendOtpRequest struct {
|
||||||
PhoneNumber string `json:"phone_number"`
|
PhoneNumber string `json:"phone_number" example:"09198829528"`
|
||||||
}
|
}
|
||||||
type SendOtpResponse struct {
|
type SendOtpResponse struct {
|
||||||
PhoneNumber string `json:"phone_number"`
|
PhoneNumber string `json:"phone_number" example:"09198829528"`
|
||||||
/*
|
/*
|
||||||
this just use in test env
|
this just use in test .env
|
||||||
TODO - remove it after test
|
TODO - remove it after test
|
||||||
*/
|
*/
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package benefactoreparam
|
package benefactoreparam
|
||||||
|
|
||||||
type Tokens struct {
|
type Tokens struct {
|
||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token" `
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,12 +36,12 @@ func (d *DB) GetAddressByID(ctx context.Context, id uint) (*entity.Address, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanAddress(scanner mysql.Scanner) (entity.Address, error) {
|
func scanAddress(scanner mysql.Scanner) (entity.Address, error) {
|
||||||
var createdAt time.Time
|
var createdAt, updatedAt time.Time
|
||||||
var address entity.Address
|
var address entity.Address
|
||||||
|
|
||||||
err := scanner.Scan(&address.ID, &address.PostalCode, &address.Address, &address.Lat, &address.Lon,
|
err := scanner.Scan(&address.ID, &address.PostalCode, &address.Address, &address.Lat, &address.Lon,
|
||||||
&address.ProvinceID, &address.CityID, &address.BenefactorID,
|
&address.IsMain, &address.CityID, &address.ProvinceID, &address.BenefactorID,
|
||||||
&createdAt)
|
&createdAt, &updatedAt)
|
||||||
|
|
||||||
return address, err
|
return address, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ func scanCity(scanner mysql.Scanner) (entity.City, error) {
|
||||||
var createdAt time.Time
|
var createdAt time.Time
|
||||||
var city entity.City
|
var city entity.City
|
||||||
|
|
||||||
err := scanner.Scan(&city.ID, &city.ProvinceID, &city.Name, &createdAt)
|
err := scanner.Scan(&city.ID, &city.Name, &city.ProvinceID, &createdAt)
|
||||||
|
|
||||||
return city, err
|
return city, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, build with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||||
|
.glide/
|
||||||
|
|
||||||
|
bin/
|
|
@ -0,0 +1,9 @@
|
||||||
|
language: go
|
||||||
|
sudo: false
|
||||||
|
go:
|
||||||
|
- 1.9.x
|
||||||
|
before_install:
|
||||||
|
- go get github.com/mattn/goveralls
|
||||||
|
script:
|
||||||
|
- $HOME/gopath/bin/goveralls -service=travis-ci
|
||||||
|
#script: go test $(go list ./... | grep -v vendor/)
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Kyle Banks
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,32 @@
|
||||||
|
VERSION = 1.2.1
|
||||||
|
|
||||||
|
RELEASE_PKG = ./cmd/depth
|
||||||
|
INSTALL_PKG = $(RELEASE_PKG)
|
||||||
|
|
||||||
|
|
||||||
|
# Remote includes require 'mmake'
|
||||||
|
# github.com/tj/mmake
|
||||||
|
include github.com/KyleBanks/make/go/install
|
||||||
|
include github.com/KyleBanks/make/go/sanity
|
||||||
|
include github.com/KyleBanks/make/go/release
|
||||||
|
include github.com/KyleBanks/make/go/bench
|
||||||
|
include github.com/KyleBanks/make/git/precommit
|
||||||
|
|
||||||
|
# Runs a number of depth commands as examples of what's possible.
|
||||||
|
example: | install
|
||||||
|
depth github.com/KyleBanks/depth/cmd/depth strings ./
|
||||||
|
|
||||||
|
depth -internal strings
|
||||||
|
|
||||||
|
depth -json github.com/KyleBanks/depth/cmd/depth
|
||||||
|
|
||||||
|
depth -test github.com/KyleBanks/depth/cmd/depth
|
||||||
|
|
||||||
|
depth -test -internal strings
|
||||||
|
|
||||||
|
depth -test -internal -max 3 strings
|
||||||
|
|
||||||
|
depth .
|
||||||
|
|
||||||
|
depth ./cmd/depth
|
||||||
|
.PHONY: example
|
|
@ -0,0 +1,232 @@
|
||||||
|
# depth
|
||||||
|
|
||||||
|
[![GoDoc](https://godoc.org/github.com/KyleBanks/depth?status.svg)](https://godoc.org/github.com/KyleBanks/depth)
|
||||||
|
[![Build Status](https://travis-ci.org/KyleBanks/depth.svg?branch=master)](https://travis-ci.org/KyleBanks/depth)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/KyleBanks/depth)](https://goreportcard.com/report/github.com/KyleBanks/depth)
|
||||||
|
[![Coverage Status](https://coveralls.io/repos/github/KyleBanks/depth/badge.svg?branch=master)](https://coveralls.io/github/KyleBanks/depth?branch=master)
|
||||||
|
|
||||||
|
`depth` is tool to retrieve and visualize Go source code dependency trees.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Download the appropriate binary for your platform from the [Releases](https://github.com/KyleBanks/depth/releases) page, or:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go get github.com/KyleBanks/depth/cmd/depth
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
`depth` can be used as a standalone command-line application, or as a package within your own project.
|
||||||
|
|
||||||
|
### Command-Line
|
||||||
|
|
||||||
|
Simply execute `depth` with one or more package names to visualize. You can use the fully qualified import path of the package, like so:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ depth github.com/KyleBanks/depth/cmd/depth
|
||||||
|
github.com/KyleBanks/depth/cmd/depth
|
||||||
|
├ encoding/json
|
||||||
|
├ flag
|
||||||
|
├ fmt
|
||||||
|
├ io
|
||||||
|
├ log
|
||||||
|
├ os
|
||||||
|
├ strings
|
||||||
|
└ github.com/KyleBanks/depth
|
||||||
|
├ fmt
|
||||||
|
├ go/build
|
||||||
|
├ path
|
||||||
|
├ sort
|
||||||
|
└ strings
|
||||||
|
12 dependencies (11 internal, 1 external, 0 testing).
|
||||||
|
```
|
||||||
|
|
||||||
|
Or you can use a relative path, for example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ depth .
|
||||||
|
$ depth ./cmd/depth
|
||||||
|
$ depth ../
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also use `depth` on the Go standard library:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ depth strings
|
||||||
|
strings
|
||||||
|
├ errors
|
||||||
|
├ io
|
||||||
|
├ unicode
|
||||||
|
└ unicode/utf8
|
||||||
|
5 dependencies (5 internal, 0 external, 0 testing).
|
||||||
|
```
|
||||||
|
|
||||||
|
Visualizing multiple packages at a time is supported by simply naming the packages you'd like to visualize:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ depth strings github.com/KyleBanks/depth
|
||||||
|
strings
|
||||||
|
├ errors
|
||||||
|
├ io
|
||||||
|
├ unicode
|
||||||
|
└ unicode/utf8
|
||||||
|
5 dependencies (5 internal, 0 external, 0 testing).
|
||||||
|
github.com/KyleBanks/depth
|
||||||
|
├ fmt
|
||||||
|
├ go/build
|
||||||
|
├ path
|
||||||
|
├ sort
|
||||||
|
└ strings
|
||||||
|
7 dependencies (7 internal, 0 external, 0 testing).
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `-internal`
|
||||||
|
|
||||||
|
By default, `depth` only resolves the top level of dependencies for standard library packages, however you can use the `-internal` flag to visualize all internal dependencies:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ depth -internal strings
|
||||||
|
strings
|
||||||
|
├ errors
|
||||||
|
├ io
|
||||||
|
├ errors
|
||||||
|
└ sync
|
||||||
|
├ internal/race
|
||||||
|
└ unsafe
|
||||||
|
├ runtime
|
||||||
|
├ runtime/internal/atomic
|
||||||
|
└ unsafe
|
||||||
|
├ runtime/internal/sys
|
||||||
|
└ unsafe
|
||||||
|
├ sync/atomic
|
||||||
|
└ unsafe
|
||||||
|
└ unsafe
|
||||||
|
├ unicode
|
||||||
|
└ unicode/utf8
|
||||||
|
12 dependencies (12 internal, 0 external, 0 testing).
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `-max`
|
||||||
|
|
||||||
|
The `-max` flag limits the dependency tree to the maximum depth provided. For example, if you supply `-max 1` on the `depth` package, your output would look like so:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ depth -max 1 github.com/KyleBanks/depth/cmd/depth
|
||||||
|
github.com/KyleBanks/depth/cmd/depth
|
||||||
|
├ encoding/json
|
||||||
|
├ flag
|
||||||
|
├ fmt
|
||||||
|
├ io
|
||||||
|
├ log
|
||||||
|
├ os
|
||||||
|
├ strings
|
||||||
|
└ github.com/KyleBanks/depth
|
||||||
|
7 dependencies (6 internal, 1 external, 0 testing).
|
||||||
|
```
|
||||||
|
|
||||||
|
The `-max` flag is particularly useful in conjunction with the `-internal` flag which can lead to very deep dependency trees.
|
||||||
|
|
||||||
|
#### `-test`
|
||||||
|
|
||||||
|
By default, `depth` ignores dependencies that are only required for testing. However, you can view test dependencies using the `-test` flag:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ depth -test strings
|
||||||
|
strings
|
||||||
|
├ bytes
|
||||||
|
├ errors
|
||||||
|
├ fmt
|
||||||
|
├ io
|
||||||
|
├ io/ioutil
|
||||||
|
├ math/rand
|
||||||
|
├ reflect
|
||||||
|
├ sync
|
||||||
|
├ testing
|
||||||
|
├ unicode
|
||||||
|
├ unicode/utf8
|
||||||
|
└ unsafe
|
||||||
|
13 dependencies (13 internal, 0 external, 8 testing).
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `-explain target-package`
|
||||||
|
|
||||||
|
The `-explain` flag instructs `depth` to print import chains in which the
|
||||||
|
`target-package` is found:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ depth -explain strings github.com/KyleBanks/depth/cmd/depth
|
||||||
|
github.com/KyleBanks/depth/cmd/depth -> strings
|
||||||
|
github.com/KyleBanks/depth/cmd/depth -> github.com/KyleBanks/depth -> strings
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `-json`
|
||||||
|
|
||||||
|
The `-json` flag instructs `depth` to output dependencies in JSON format:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ depth -json github.com/KyleBanks/depth/cmd/depth
|
||||||
|
{
|
||||||
|
"name": "github.com/KyleBanks/depth/cmd/depth",
|
||||||
|
"deps": [
|
||||||
|
{
|
||||||
|
"name": "encoding/json",
|
||||||
|
"internal": true,
|
||||||
|
"deps": null
|
||||||
|
},
|
||||||
|
...
|
||||||
|
{
|
||||||
|
"name": "github.com/KyleBanks/depth",
|
||||||
|
"internal": false,
|
||||||
|
"deps": [
|
||||||
|
{
|
||||||
|
"name": "go/build",
|
||||||
|
"internal": true,
|
||||||
|
"deps": null
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integrating With Your Project
|
||||||
|
|
||||||
|
The `depth` package can easily be used to retrieve the dependency tree for a particular package in your own project. For example, here's how you would retrieve the dependency tree for the `strings` package:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/KyleBanks/depth"
|
||||||
|
|
||||||
|
var t depth.Tree
|
||||||
|
err := t.Resolve("strings")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output: "'strings' has 4 dependencies."
|
||||||
|
log.Printf("'%v' has %v dependencies.", t.Root.Name, len(t.Root.Deps))
|
||||||
|
```
|
||||||
|
|
||||||
|
For additional customization, simply set the appropriate flags on the `Tree` before resolving:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/KyleBanks/depth"
|
||||||
|
|
||||||
|
t := depth.Tree {
|
||||||
|
ResolveInternal: true,
|
||||||
|
ResolveTest: true,
|
||||||
|
MaxDepth: 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
err := t.Resolve("strings")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
`depth` was developed by [Kyle Banks](https://twitter.com/kylewbanks).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
`depth` is available under the [MIT](./LICENSE) license.
|
|
@ -0,0 +1,129 @@
|
||||||
|
// Package depth provides the ability to traverse and retrieve Go source code dependencies in the form of
|
||||||
|
// internal and external packages.
|
||||||
|
//
|
||||||
|
// For example, the dependencies of the stdlib `strings` package can be resolved like so:
|
||||||
|
//
|
||||||
|
// import "github.com/KyleBanks/depth"
|
||||||
|
//
|
||||||
|
// var t depth.Tree
|
||||||
|
// err := t.Resolve("strings")
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Output: "strings has 4 dependencies."
|
||||||
|
// log.Printf("%v has %v dependencies.", t.Root.Name, len(t.Root.Deps))
|
||||||
|
//
|
||||||
|
// For additional customization, simply set the appropriate flags on the `Tree` before resolving:
|
||||||
|
//
|
||||||
|
// import "github.com/KyleBanks/depth"
|
||||||
|
//
|
||||||
|
// t := depth.Tree {
|
||||||
|
// ResolveInternal: true,
|
||||||
|
// ResolveTest: true,
|
||||||
|
// MaxDepth: 10,
|
||||||
|
// }
|
||||||
|
// err := t.Resolve("strings")
|
||||||
|
package depth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"go/build"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrRootPkgNotResolved is returned when the root Pkg of the Tree cannot be resolved,
|
||||||
|
// typically because it does not exist.
|
||||||
|
var ErrRootPkgNotResolved = errors.New("unable to resolve root package")
|
||||||
|
|
||||||
|
// Importer defines a type that can import a package and return its details.
|
||||||
|
type Importer interface {
|
||||||
|
Import(name, srcDir string, im build.ImportMode) (*build.Package, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tree represents the top level of a Pkg and the configuration used to
|
||||||
|
// initialize and represent its contents.
|
||||||
|
type Tree struct {
|
||||||
|
Root *Pkg
|
||||||
|
|
||||||
|
ResolveInternal bool
|
||||||
|
ResolveTest bool
|
||||||
|
MaxDepth int
|
||||||
|
|
||||||
|
Importer Importer
|
||||||
|
|
||||||
|
importCache map[string]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve recursively finds all dependencies for the root Pkg name provided,
|
||||||
|
// and the packages it depends on.
|
||||||
|
func (t *Tree) Resolve(name string) error {
|
||||||
|
pwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Root = &Pkg{
|
||||||
|
Name: name,
|
||||||
|
Tree: t,
|
||||||
|
SrcDir: pwd,
|
||||||
|
Test: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the import cache each time to ensure a reused Tree doesn't
|
||||||
|
// reuse the same cache.
|
||||||
|
t.importCache = nil
|
||||||
|
|
||||||
|
// Allow custom importers, but use build.Default if none is provided.
|
||||||
|
if t.Importer == nil {
|
||||||
|
t.Importer = &build.Default
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Root.Resolve(t.Importer)
|
||||||
|
if !t.Root.Resolved {
|
||||||
|
return ErrRootPkgNotResolved
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// shouldResolveInternal determines if internal packages should be further resolved beyond the
|
||||||
|
// current parent.
|
||||||
|
//
|
||||||
|
// For example, if the parent Pkg is `github.com/foo/bar` and true is returned, all the
|
||||||
|
// internal dependencies it relies on will be resolved. If for example `strings` is one of those
|
||||||
|
// dependencies, and it is passed as the parent here, false may be returned and its internal
|
||||||
|
// dependencies will not be resolved.
|
||||||
|
func (t *Tree) shouldResolveInternal(parent *Pkg) bool {
|
||||||
|
if t.ResolveInternal {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent == t.Root
|
||||||
|
}
|
||||||
|
|
||||||
|
// isAtMaxDepth returns true when the depth of the Pkg provided is at or beyond the maximum
|
||||||
|
// depth allowed by the tree.
|
||||||
|
//
|
||||||
|
// If the Tree has a MaxDepth of zero, true is never returned.
|
||||||
|
func (t *Tree) isAtMaxDepth(p *Pkg) bool {
|
||||||
|
if t.MaxDepth == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.depth() >= t.MaxDepth
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasSeenImport returns true if the import name provided has already been seen within the tree.
|
||||||
|
// This function only returns false for a name once.
|
||||||
|
func (t *Tree) hasSeenImport(name string) bool {
|
||||||
|
if t.importCache == nil {
|
||||||
|
t.importCache = make(map[string]struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := t.importCache[name]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
t.importCache[name] = struct{}{}
|
||||||
|
return false
|
||||||
|
}
|
|
@ -0,0 +1,184 @@
|
||||||
|
package depth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"go/build"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Pkg represents a Go source package, and its dependencies.
|
||||||
|
type Pkg struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
SrcDir string `json:"-"`
|
||||||
|
|
||||||
|
Internal bool `json:"internal"`
|
||||||
|
Resolved bool `json:"resolved"`
|
||||||
|
Test bool `json:"-"`
|
||||||
|
|
||||||
|
Tree *Tree `json:"-"`
|
||||||
|
Parent *Pkg `json:"-"`
|
||||||
|
Deps []Pkg `json:"deps"`
|
||||||
|
|
||||||
|
Raw *build.Package `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve recursively finds all dependencies for the Pkg and the packages it depends on.
|
||||||
|
func (p *Pkg) Resolve(i Importer) {
|
||||||
|
// Resolved is always true, regardless of if we skip the import,
|
||||||
|
// it is only false if there is an error while importing.
|
||||||
|
p.Resolved = true
|
||||||
|
|
||||||
|
name := p.cleanName()
|
||||||
|
if name == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop resolving imports if we've reached max depth or found a duplicate.
|
||||||
|
var importMode build.ImportMode
|
||||||
|
if p.Tree.hasSeenImport(name) || p.Tree.isAtMaxDepth(p) {
|
||||||
|
importMode = build.FindOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg, err := i.Import(name, p.SrcDir, importMode)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: Check the error type?
|
||||||
|
p.Resolved = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Raw = pkg
|
||||||
|
|
||||||
|
// Update the name with the fully qualified import path.
|
||||||
|
p.Name = pkg.ImportPath
|
||||||
|
|
||||||
|
// If this is an internal dependency, we may need to skip it.
|
||||||
|
if pkg.Goroot {
|
||||||
|
p.Internal = true
|
||||||
|
if !p.Tree.shouldResolveInternal(p) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//first we set the regular dependencies, then we add the test dependencies
|
||||||
|
//sharing the same set. This allows us to mark all test-only deps linearly
|
||||||
|
unique := make(map[string]struct{})
|
||||||
|
p.setDeps(i, pkg.Imports, pkg.Dir, unique, false)
|
||||||
|
if p.Tree.ResolveTest {
|
||||||
|
p.setDeps(i, append(pkg.TestImports, pkg.XTestImports...), pkg.Dir, unique, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setDeps takes a slice of import paths and the source directory they are relative to,
|
||||||
|
// and creates the Deps of the Pkg. Each dependency is also further resolved prior to being added
|
||||||
|
// to the Pkg.
|
||||||
|
func (p *Pkg) setDeps(i Importer, imports []string, srcDir string, unique map[string]struct{}, isTest bool) {
|
||||||
|
for _, imp := range imports {
|
||||||
|
// Mostly for testing files where cyclic imports are allowed.
|
||||||
|
if imp == p.Name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip duplicates.
|
||||||
|
if _, ok := unique[imp]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
unique[imp] = struct{}{}
|
||||||
|
|
||||||
|
p.addDep(i, imp, srcDir, isTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(byInternalAndName(p.Deps))
|
||||||
|
}
|
||||||
|
|
||||||
|
// addDep creates a Pkg and it's dependencies from an imported package name.
|
||||||
|
func (p *Pkg) addDep(i Importer, name string, srcDir string, isTest bool) {
|
||||||
|
dep := Pkg{
|
||||||
|
Name: name,
|
||||||
|
SrcDir: srcDir,
|
||||||
|
Tree: p.Tree,
|
||||||
|
Parent: p,
|
||||||
|
Test: isTest,
|
||||||
|
}
|
||||||
|
dep.Resolve(i)
|
||||||
|
|
||||||
|
p.Deps = append(p.Deps, dep)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isParent goes recursively up the chain of Pkgs to determine if the name provided is ever a
|
||||||
|
// parent of the current Pkg.
|
||||||
|
func (p *Pkg) isParent(name string) bool {
|
||||||
|
if p.Parent == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Parent.Name == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.Parent.isParent(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// depth returns the depth of the Pkg within the Tree.
|
||||||
|
func (p *Pkg) depth() int {
|
||||||
|
if p.Parent == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.Parent.depth() + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanName returns a cleaned version of the Pkg name used for resolving dependencies.
|
||||||
|
//
|
||||||
|
// If an empty string is returned, dependencies should not be resolved.
|
||||||
|
func (p *Pkg) cleanName() string {
|
||||||
|
name := p.Name
|
||||||
|
|
||||||
|
// C 'package' cannot be resolved.
|
||||||
|
if name == "C" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal golang_org/* packages must be prefixed with vendor/
|
||||||
|
//
|
||||||
|
// Thanks to @davecheney for this:
|
||||||
|
// https://github.com/davecheney/graphpkg/blob/master/main.go#L46
|
||||||
|
if strings.HasPrefix(name, "golang_org") {
|
||||||
|
name = path.Join("vendor", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of the Pkg containing the Pkg name and status.
|
||||||
|
func (p *Pkg) String() string {
|
||||||
|
b := bytes.NewBufferString(p.Name)
|
||||||
|
|
||||||
|
if !p.Resolved {
|
||||||
|
b.Write([]byte(" (unresolved)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// byInternalAndName ensures a slice of Pkgs are sorted such that the internal stdlib
|
||||||
|
// packages are always above external packages (ie. github.com/whatever).
|
||||||
|
type byInternalAndName []Pkg
|
||||||
|
|
||||||
|
func (b byInternalAndName) Len() int {
|
||||||
|
return len(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b byInternalAndName) Swap(i, j int) {
|
||||||
|
b[i], b[j] = b[j], b[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b byInternalAndName) Less(i, j int) bool {
|
||||||
|
if b[i].Internal && !b[j].Internal {
|
||||||
|
return true
|
||||||
|
} else if !b[i].Internal && b[j].Internal {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return b[i].Name < b[j].Name
|
||||||
|
}
|
|
@ -72,13 +72,13 @@ var ParamTagMap = map[string]ParamValidator{
|
||||||
|
|
||||||
// ParamTagRegexMap maps param tags to their respective regexes.
|
// ParamTagRegexMap maps param tags to their respective regexes.
|
||||||
var ParamTagRegexMap = map[string]*regexp.Regexp{
|
var ParamTagRegexMap = map[string]*regexp.Regexp{
|
||||||
"range": regexp.MustCompile("^range\\((\\d+)\\|(\\d+)\\)$"),
|
"range": regexp.MustCompile("^range\\((\\d+)\\|(\\d+)\\)$"),
|
||||||
"length": regexp.MustCompile("^length\\((\\d+)\\|(\\d+)\\)$"),
|
"length": regexp.MustCompile("^length\\((\\d+)\\|(\\d+)\\)$"),
|
||||||
"runelength": regexp.MustCompile("^runelength\\((\\d+)\\|(\\d+)\\)$"),
|
"runelength": regexp.MustCompile("^runelength\\((\\d+)\\|(\\d+)\\)$"),
|
||||||
"stringlength": regexp.MustCompile("^stringlength\\((\\d+)\\|(\\d+)\\)$"),
|
"stringlength": regexp.MustCompile("^stringlength\\((\\d+)\\|(\\d+)\\)$"),
|
||||||
"in": regexp.MustCompile(`^in\((.*)\)`),
|
"in": regexp.MustCompile(`^in\((.*)\)`),
|
||||||
"matches": regexp.MustCompile(`^matches\((.+)\)$`),
|
"matches": regexp.MustCompile(`^matches\((.+)\)$`),
|
||||||
"rsapub": regexp.MustCompile("^rsapub\\((\\d+)\\)$"),
|
"rsapub": regexp.MustCompile("^rsapub\\((\\d+)\\)$"),
|
||||||
"minstringlength": regexp.MustCompile("^minstringlength\\((\\d+)\\)$"),
|
"minstringlength": regexp.MustCompile("^minstringlength\\((\\d+)\\)$"),
|
||||||
"maxstringlength": regexp.MustCompile("^maxstringlength\\((\\d+)\\)$"),
|
"maxstringlength": regexp.MustCompile("^maxstringlength\\((\\d+)\\)$"),
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ type ISO3166Entry struct {
|
||||||
Numeric string
|
Numeric string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ISO3166List based on https://www.iso.org/obp/ui/#search/code/ Code Type "Officially Assigned Codes"
|
//ISO3166List based on https://www.iso.org/obp/ui/#search/code/ Code Type "Officially Assigned Codes"
|
||||||
var ISO3166List = []ISO3166Entry{
|
var ISO3166List = []ISO3166Entry{
|
||||||
{"Afghanistan", "Afghanistan (l')", "AF", "AFG", "004"},
|
{"Afghanistan", "Afghanistan (l')", "AF", "AFG", "004"},
|
||||||
{"Albania", "Albanie (l')", "AL", "ALB", "008"},
|
{"Albania", "Albanie (l')", "AL", "ALB", "008"},
|
||||||
|
@ -463,7 +463,7 @@ type ISO693Entry struct {
|
||||||
English string
|
English string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ISO693List based on http://data.okfn.org/data/core/language-codes/r/language-codes-3b2.json
|
//ISO693List based on http://data.okfn.org/data/core/language-codes/r/language-codes-3b2.json
|
||||||
var ISO693List = []ISO693Entry{
|
var ISO693List = []ISO693Entry{
|
||||||
{Alpha3bCode: "aar", Alpha2Code: "aa", English: "Afar"},
|
{Alpha3bCode: "aar", Alpha2Code: "aa", English: "Afar"},
|
||||||
{Alpha3bCode: "abk", Alpha2Code: "ab", English: "Abkhazian"},
|
{Alpha3bCode: "abk", Alpha2Code: "ab", English: "Abkhazian"},
|
||||||
|
|
|
@ -37,32 +37,25 @@ const RF3339WithoutZone = "2006-01-02T15:04:05"
|
||||||
// SetFieldsRequiredByDefault causes validation to fail when struct fields
|
// SetFieldsRequiredByDefault causes validation to fail when struct fields
|
||||||
// do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`).
|
// do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`).
|
||||||
// This struct definition will fail govalidator.ValidateStruct() (and the field values do not matter):
|
// This struct definition will fail govalidator.ValidateStruct() (and the field values do not matter):
|
||||||
//
|
// type exampleStruct struct {
|
||||||
// type exampleStruct struct {
|
// Name string ``
|
||||||
// Name string ``
|
// Email string `valid:"email"`
|
||||||
// Email string `valid:"email"`
|
|
||||||
//
|
|
||||||
// This, however, will only fail when Email is empty or an invalid email address:
|
// This, however, will only fail when Email is empty or an invalid email address:
|
||||||
//
|
// type exampleStruct2 struct {
|
||||||
// type exampleStruct2 struct {
|
// Name string `valid:"-"`
|
||||||
// Name string `valid:"-"`
|
// Email string `valid:"email"`
|
||||||
// Email string `valid:"email"`
|
|
||||||
//
|
|
||||||
// Lastly, this will only fail when Email is an invalid email address but not when it's empty:
|
// Lastly, this will only fail when Email is an invalid email address but not when it's empty:
|
||||||
//
|
// type exampleStruct2 struct {
|
||||||
// type exampleStruct2 struct {
|
// Name string `valid:"-"`
|
||||||
// Name string `valid:"-"`
|
// Email string `valid:"email,optional"`
|
||||||
// Email string `valid:"email,optional"`
|
|
||||||
func SetFieldsRequiredByDefault(value bool) {
|
func SetFieldsRequiredByDefault(value bool) {
|
||||||
fieldsRequiredByDefault = value
|
fieldsRequiredByDefault = value
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNilPtrAllowedByRequired causes validation to pass for nil ptrs when a field is set to required.
|
// SetNilPtrAllowedByRequired causes validation to pass for nil ptrs when a field is set to required.
|
||||||
// The validation will still reject ptr fields in their zero value state. Example with this enabled:
|
// The validation will still reject ptr fields in their zero value state. Example with this enabled:
|
||||||
//
|
// type exampleStruct struct {
|
||||||
// type exampleStruct struct {
|
// Name *string `valid:"required"`
|
||||||
// Name *string `valid:"required"`
|
|
||||||
//
|
|
||||||
// With `Name` set to "", this will be considered invalid input and will cause a validation error.
|
// With `Name` set to "", this will be considered invalid input and will cause a validation error.
|
||||||
// With `Name` set to nil, this will be considered valid by validation.
|
// With `Name` set to nil, this will be considered valid by validation.
|
||||||
// By default this is disabled.
|
// By default this is disabled.
|
||||||
|
@ -161,8 +154,8 @@ func IsAlpha(str string) bool {
|
||||||
return rxAlpha.MatchString(str)
|
return rxAlpha.MatchString(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsUTFLetter check if the string contains only unicode letter characters.
|
//IsUTFLetter check if the string contains only unicode letter characters.
|
||||||
// Similar to IsAlpha but for all languages. Empty string is valid.
|
//Similar to IsAlpha but for all languages. Empty string is valid.
|
||||||
func IsUTFLetter(str string) bool {
|
func IsUTFLetter(str string) bool {
|
||||||
if IsNull(str) {
|
if IsNull(str) {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -3,12 +3,13 @@ package gofakeit
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TemplateOptions defines values needed for template document generation
|
// TemplateOptions defines values needed for template document generation
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
// tag is deprecated and thus should not be used.
|
// tag is deprecated and thus should not be used.
|
||||||
// Go versions prior to 1.4 are disabled because they use a different layout
|
// Go versions prior to 1.4 are disabled because they use a different layout
|
||||||
// for interfaces which make the implementation of unsafeReflectValue more complex.
|
// for interfaces which make the implementation of unsafeReflectValue more complex.
|
||||||
//go:build !js && !appengine && !safe && !disableunsafe && go1.4
|
|
||||||
// +build !js,!appengine,!safe,!disableunsafe,go1.4
|
// +build !js,!appengine,!safe,!disableunsafe,go1.4
|
||||||
|
|
||||||
package spew
|
package spew
|
||||||
|
|
|
@ -254,15 +254,15 @@ pointer addresses used to indirect to the final value. It provides the
|
||||||
following features over the built-in printing facilities provided by the fmt
|
following features over the built-in printing facilities provided by the fmt
|
||||||
package:
|
package:
|
||||||
|
|
||||||
- Pointers are dereferenced and followed
|
* Pointers are dereferenced and followed
|
||||||
- Circular data structures are detected and handled properly
|
* Circular data structures are detected and handled properly
|
||||||
- Custom Stringer/error interfaces are optionally invoked, including
|
* Custom Stringer/error interfaces are optionally invoked, including
|
||||||
on unexported types
|
on unexported types
|
||||||
- Custom types which only implement the Stringer/error interfaces via
|
* Custom types which only implement the Stringer/error interfaces via
|
||||||
a pointer receiver are optionally invoked when passing non-pointer
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
variables
|
variables
|
||||||
- Byte arrays and slices are dumped like the hexdump -C command which
|
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||||
includes offsets, byte values in hex, and ASCII output
|
includes offsets, byte values in hex, and ASCII output
|
||||||
|
|
||||||
The configuration options are controlled by modifying the public members
|
The configuration options are controlled by modifying the public members
|
||||||
of c. See ConfigState for options documentation.
|
of c. See ConfigState for options documentation.
|
||||||
|
@ -295,12 +295,12 @@ func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{})
|
||||||
|
|
||||||
// NewDefaultConfig returns a ConfigState with the following default settings.
|
// NewDefaultConfig returns a ConfigState with the following default settings.
|
||||||
//
|
//
|
||||||
// Indent: " "
|
// Indent: " "
|
||||||
// MaxDepth: 0
|
// MaxDepth: 0
|
||||||
// DisableMethods: false
|
// DisableMethods: false
|
||||||
// DisablePointerMethods: false
|
// DisablePointerMethods: false
|
||||||
// ContinueOnMethod: false
|
// ContinueOnMethod: false
|
||||||
// SortKeys: false
|
// SortKeys: false
|
||||||
func NewDefaultConfig() *ConfigState {
|
func NewDefaultConfig() *ConfigState {
|
||||||
return &ConfigState{Indent: " "}
|
return &ConfigState{Indent: " "}
|
||||||
}
|
}
|
||||||
|
|
|
@ -488,15 +488,15 @@ pointer addresses used to indirect to the final value. It provides the
|
||||||
following features over the built-in printing facilities provided by the fmt
|
following features over the built-in printing facilities provided by the fmt
|
||||||
package:
|
package:
|
||||||
|
|
||||||
- Pointers are dereferenced and followed
|
* Pointers are dereferenced and followed
|
||||||
- Circular data structures are detected and handled properly
|
* Circular data structures are detected and handled properly
|
||||||
- Custom Stringer/error interfaces are optionally invoked, including
|
* Custom Stringer/error interfaces are optionally invoked, including
|
||||||
on unexported types
|
on unexported types
|
||||||
- Custom types which only implement the Stringer/error interfaces via
|
* Custom types which only implement the Stringer/error interfaces via
|
||||||
a pointer receiver are optionally invoked when passing non-pointer
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
variables
|
variables
|
||||||
- Byte arrays and slices are dumped like the hexdump -C command which
|
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||||
includes offsets, byte values in hex, and ASCII output
|
includes offsets, byte values in hex, and ASCII output
|
||||||
|
|
||||||
The configuration options are controlled by an exported package global,
|
The configuration options are controlled by an exported package global,
|
||||||
spew.Config. See ConfigState for options documentation.
|
spew.Config. See ConfigState for options documentation.
|
||||||
|
|
|
@ -95,8 +95,8 @@ func (f *Field) Zero() error {
|
||||||
// of a nested struct . A struct tag with the content of "-" ignores the
|
// of a nested struct . A struct tag with the content of "-" ignores the
|
||||||
// checking of that particular field. Example:
|
// checking of that particular field. Example:
|
||||||
//
|
//
|
||||||
// // Field is ignored by this package.
|
// // Field is ignored by this package.
|
||||||
// Field *http.Request `structs:"-"`
|
// Field *http.Request `structs:"-"`
|
||||||
//
|
//
|
||||||
// It panics if field is not exported or if field's kind is not struct
|
// It panics if field is not exported or if field's kind is not struct
|
||||||
func (f *Field) Fields() []*Field {
|
func (f *Field) Fields() []*Field {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,43 +38,43 @@ func New(s interface{}) *Struct {
|
||||||
// can be changed in the struct field's tag value. The "structs" key in the
|
// can be changed in the struct field's tag value. The "structs" key in the
|
||||||
// struct's field tag value is the key name. Example:
|
// struct's field tag value is the key name. Example:
|
||||||
//
|
//
|
||||||
// // Field appears in map as key "myName".
|
// // Field appears in map as key "myName".
|
||||||
// Name string `structs:"myName"`
|
// Name string `structs:"myName"`
|
||||||
//
|
//
|
||||||
// A tag value with the content of "-" ignores that particular field. Example:
|
// A tag value with the content of "-" ignores that particular field. Example:
|
||||||
//
|
//
|
||||||
// // Field is ignored by this package.
|
// // Field is ignored by this package.
|
||||||
// Field bool `structs:"-"`
|
// Field bool `structs:"-"`
|
||||||
//
|
//
|
||||||
// A tag value with the content of "string" uses the stringer to get the value. Example:
|
// A tag value with the content of "string" uses the stringer to get the value. Example:
|
||||||
//
|
//
|
||||||
// // The value will be output of Animal's String() func.
|
// // The value will be output of Animal's String() func.
|
||||||
// // Map will panic if Animal does not implement String().
|
// // Map will panic if Animal does not implement String().
|
||||||
// Field *Animal `structs:"field,string"`
|
// Field *Animal `structs:"field,string"`
|
||||||
//
|
//
|
||||||
// A tag value with the option of "flatten" used in a struct field is to flatten its fields
|
// A tag value with the option of "flatten" used in a struct field is to flatten its fields
|
||||||
// in the output map. Example:
|
// in the output map. Example:
|
||||||
//
|
//
|
||||||
// // The FieldStruct's fields will be flattened into the output map.
|
// // The FieldStruct's fields will be flattened into the output map.
|
||||||
// FieldStruct time.Time `structs:",flatten"`
|
// FieldStruct time.Time `structs:",flatten"`
|
||||||
//
|
//
|
||||||
// A tag value with the option of "omitnested" stops iterating further if the type
|
// A tag value with the option of "omitnested" stops iterating further if the type
|
||||||
// is a struct. Example:
|
// is a struct. Example:
|
||||||
//
|
//
|
||||||
// // Field is not processed further by this package.
|
// // Field is not processed further by this package.
|
||||||
// Field time.Time `structs:"myName,omitnested"`
|
// Field time.Time `structs:"myName,omitnested"`
|
||||||
// Field *http.Request `structs:",omitnested"`
|
// Field *http.Request `structs:",omitnested"`
|
||||||
//
|
//
|
||||||
// A tag value with the option of "omitempty" ignores that particular field if
|
// A tag value with the option of "omitempty" ignores that particular field if
|
||||||
// the field value is empty. Example:
|
// the field value is empty. Example:
|
||||||
//
|
//
|
||||||
// // Field appears in map as key "myName", but the field is
|
// // Field appears in map as key "myName", but the field is
|
||||||
// // skipped if empty.
|
// // skipped if empty.
|
||||||
// Field string `structs:"myName,omitempty"`
|
// Field string `structs:"myName,omitempty"`
|
||||||
//
|
//
|
||||||
// // Field appears in map as key "Field" (the default), but
|
// // Field appears in map as key "Field" (the default), but
|
||||||
// // the field is skipped if empty.
|
// // the field is skipped if empty.
|
||||||
// Field string `structs:",omitempty"`
|
// Field string `structs:",omitempty"`
|
||||||
//
|
//
|
||||||
// Note that only exported fields of a struct can be accessed, non exported
|
// Note that only exported fields of a struct can be accessed, non exported
|
||||||
// fields will be neglected.
|
// fields will be neglected.
|
||||||
|
@ -152,21 +153,21 @@ func (s *Struct) FillMap(out map[string]interface{}) {
|
||||||
// struct tag with the content of "-" ignores the that particular field.
|
// struct tag with the content of "-" ignores the that particular field.
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// // Field is ignored by this package.
|
// // Field is ignored by this package.
|
||||||
// Field int `structs:"-"`
|
// Field int `structs:"-"`
|
||||||
//
|
//
|
||||||
// A value with the option of "omitnested" stops iterating further if the type
|
// A value with the option of "omitnested" stops iterating further if the type
|
||||||
// is a struct. Example:
|
// is a struct. Example:
|
||||||
//
|
//
|
||||||
// // Fields is not processed further by this package.
|
// // Fields is not processed further by this package.
|
||||||
// Field time.Time `structs:",omitnested"`
|
// Field time.Time `structs:",omitnested"`
|
||||||
// Field *http.Request `structs:",omitnested"`
|
// Field *http.Request `structs:",omitnested"`
|
||||||
//
|
//
|
||||||
// A tag value with the option of "omitempty" ignores that particular field and
|
// A tag value with the option of "omitempty" ignores that particular field and
|
||||||
// is not added to the values if the field value is empty. Example:
|
// is not added to the values if the field value is empty. Example:
|
||||||
//
|
//
|
||||||
// // Field is skipped if empty
|
// // Field is skipped if empty
|
||||||
// Field string `structs:",omitempty"`
|
// Field string `structs:",omitempty"`
|
||||||
//
|
//
|
||||||
// Note that only exported fields of a struct can be accessed, non exported
|
// Note that only exported fields of a struct can be accessed, non exported
|
||||||
// fields will be neglected.
|
// fields will be neglected.
|
||||||
|
@ -214,8 +215,8 @@ func (s *Struct) Values() []interface{} {
|
||||||
// Fields returns a slice of Fields. A struct tag with the content of "-"
|
// Fields returns a slice of Fields. A struct tag with the content of "-"
|
||||||
// ignores the checking of that particular field. Example:
|
// ignores the checking of that particular field. Example:
|
||||||
//
|
//
|
||||||
// // Field is ignored by this package.
|
// // Field is ignored by this package.
|
||||||
// Field bool `structs:"-"`
|
// Field bool `structs:"-"`
|
||||||
//
|
//
|
||||||
// It panics if s's kind is not struct.
|
// It panics if s's kind is not struct.
|
||||||
func (s *Struct) Fields() []*Field {
|
func (s *Struct) Fields() []*Field {
|
||||||
|
@ -225,8 +226,8 @@ func (s *Struct) Fields() []*Field {
|
||||||
// Names returns a slice of field names. A struct tag with the content of "-"
|
// Names returns a slice of field names. A struct tag with the content of "-"
|
||||||
// ignores the checking of that particular field. Example:
|
// ignores the checking of that particular field. Example:
|
||||||
//
|
//
|
||||||
// // Field is ignored by this package.
|
// // Field is ignored by this package.
|
||||||
// Field bool `structs:"-"`
|
// Field bool `structs:"-"`
|
||||||
//
|
//
|
||||||
// It panics if s's kind is not struct.
|
// It panics if s's kind is not struct.
|
||||||
func (s *Struct) Names() []string {
|
func (s *Struct) Names() []string {
|
||||||
|
@ -302,15 +303,15 @@ func (s *Struct) FieldOk(name string) (*Field, bool) {
|
||||||
// initialized) A struct tag with the content of "-" ignores the checking of
|
// initialized) A struct tag with the content of "-" ignores the checking of
|
||||||
// that particular field. Example:
|
// that particular field. Example:
|
||||||
//
|
//
|
||||||
// // Field is ignored by this package.
|
// // Field is ignored by this package.
|
||||||
// Field bool `structs:"-"`
|
// Field bool `structs:"-"`
|
||||||
//
|
//
|
||||||
// A value with the option of "omitnested" stops iterating further if the type
|
// A value with the option of "omitnested" stops iterating further if the type
|
||||||
// is a struct. Example:
|
// is a struct. Example:
|
||||||
//
|
//
|
||||||
// // Field is not processed further by this package.
|
// // Field is not processed further by this package.
|
||||||
// Field time.Time `structs:"myName,omitnested"`
|
// Field time.Time `structs:"myName,omitnested"`
|
||||||
// Field *http.Request `structs:",omitnested"`
|
// Field *http.Request `structs:",omitnested"`
|
||||||
//
|
//
|
||||||
// Note that only exported fields of a struct can be accessed, non exported
|
// Note that only exported fields of a struct can be accessed, non exported
|
||||||
// fields will be neglected. It panics if s's kind is not struct.
|
// fields will be neglected. It panics if s's kind is not struct.
|
||||||
|
@ -349,15 +350,15 @@ func (s *Struct) IsZero() bool {
|
||||||
// A struct tag with the content of "-" ignores the checking of that particular
|
// A struct tag with the content of "-" ignores the checking of that particular
|
||||||
// field. Example:
|
// field. Example:
|
||||||
//
|
//
|
||||||
// // Field is ignored by this package.
|
// // Field is ignored by this package.
|
||||||
// Field bool `structs:"-"`
|
// Field bool `structs:"-"`
|
||||||
//
|
//
|
||||||
// A value with the option of "omitnested" stops iterating further if the type
|
// A value with the option of "omitnested" stops iterating further if the type
|
||||||
// is a struct. Example:
|
// is a struct. Example:
|
||||||
//
|
//
|
||||||
// // Field is not processed further by this package.
|
// // Field is not processed further by this package.
|
||||||
// Field time.Time `structs:"myName,omitnested"`
|
// Field time.Time `structs:"myName,omitnested"`
|
||||||
// Field *http.Request `structs:",omitnested"`
|
// Field *http.Request `structs:",omitnested"`
|
||||||
//
|
//
|
||||||
// Note that only exported fields of a struct can be accessed, non exported
|
// Note that only exported fields of a struct can be accessed, non exported
|
||||||
// fields will be neglected. It panics if s's kind is not struct.
|
// fields will be neglected. It panics if s's kind is not struct.
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# OSX leaves these everywhere on SMB shares
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Eclipse files
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.settings/**
|
||||||
|
|
||||||
|
# Emacs save files
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Vim-related files
|
||||||
|
[._]*.s[a-w][a-z]
|
||||||
|
[._]s[a-w][a-z]
|
||||||
|
*.un~
|
||||||
|
Session.vim
|
||||||
|
.netrwhist
|
||||||
|
|
||||||
|
# Go test binaries
|
||||||
|
*.test
|
|
@ -0,0 +1,7 @@
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
script:
|
||||||
|
- go test
|
||||||
|
- go build
|
|
@ -0,0 +1,50 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Sam Ghods
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,121 @@
|
||||||
|
# YAML marshaling and unmarshaling support for Go
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/ghodss/yaml.svg)](https://travis-ci.org/ghodss/yaml)
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs.
|
||||||
|
|
||||||
|
In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/).
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
This package uses [go-yaml](https://github.com/go-yaml/yaml) and therefore supports [everything go-yaml supports](https://github.com/go-yaml/yaml#compatibility).
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
**Caveat #1:** When using `yaml.Marshal` and `yaml.Unmarshal`, binary data should NOT be preceded with the `!!binary` YAML tag. If you do, go-yaml will convert the binary data from base64 to native binary data, which is not compatible with JSON. You can still use binary in your YAML files though - just store them without the `!!binary` tag and decode the base64 in your code (e.g. in the custom JSON methods `MarshalJSON` and `UnmarshalJSON`). This also has the benefit that your YAML and your JSON binary data will be decoded exactly the same way. As an example:
|
||||||
|
|
||||||
|
```
|
||||||
|
BAD:
|
||||||
|
exampleKey: !!binary gIGC
|
||||||
|
|
||||||
|
GOOD:
|
||||||
|
exampleKey: gIGC
|
||||||
|
... and decode the base64 data in your code.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Caveat #2:** When using `YAMLToJSON` directly, maps with keys that are maps will result in an error since this is not supported by JSON. This error will occur in `Unmarshal` as well since you can't unmarshal map keys anyways since struct fields can't be keys.
|
||||||
|
|
||||||
|
## Installation and usage
|
||||||
|
|
||||||
|
To install, run:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ go get github.com/ghodss/yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
And import using:
|
||||||
|
|
||||||
|
```
|
||||||
|
import "github.com/ghodss/yaml"
|
||||||
|
```
|
||||||
|
|
||||||
|
Usage is very similar to the JSON library:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ghodss/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Person struct {
|
||||||
|
Name string `json:"name"` // Affects YAML field names too.
|
||||||
|
Age int `json:"age"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Marshal a Person struct to YAML.
|
||||||
|
p := Person{"John", 30}
|
||||||
|
y, err := yaml.Marshal(p)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("err: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(y))
|
||||||
|
/* Output:
|
||||||
|
age: 30
|
||||||
|
name: John
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Unmarshal the YAML back into a Person struct.
|
||||||
|
var p2 Person
|
||||||
|
err = yaml.Unmarshal(y, &p2)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("err: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(p2)
|
||||||
|
/* Output:
|
||||||
|
{John 30}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`yaml.YAMLToJSON` and `yaml.JSONToYAML` methods are also available:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ghodss/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
j := []byte(`{"name": "John", "age": 30}`)
|
||||||
|
y, err := yaml.JSONToYAML(j)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("err: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(y))
|
||||||
|
/* Output:
|
||||||
|
name: John
|
||||||
|
age: 30
|
||||||
|
*/
|
||||||
|
j2, err := yaml.YAMLToJSON(y)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("err: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(j2))
|
||||||
|
/* Output:
|
||||||
|
{"age":30,"name":"John"}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,501 @@
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding"
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// indirect walks down v allocating pointers as needed,
|
||||||
|
// until it gets to a non-pointer.
|
||||||
|
// if it encounters an Unmarshaler, indirect stops and returns that.
|
||||||
|
// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
|
||||||
|
func indirect(v reflect.Value, decodingNull bool) (json.Unmarshaler, encoding.TextUnmarshaler, reflect.Value) {
|
||||||
|
// If v is a named type and is addressable,
|
||||||
|
// start with its address, so that if the type has pointer methods,
|
||||||
|
// we find them.
|
||||||
|
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
|
||||||
|
v = v.Addr()
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
// Load value from interface, but only if the result will be
|
||||||
|
// usefully addressable.
|
||||||
|
if v.Kind() == reflect.Interface && !v.IsNil() {
|
||||||
|
e := v.Elem()
|
||||||
|
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
|
||||||
|
v = e
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Kind() != reflect.Ptr {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if v.IsNil() {
|
||||||
|
if v.CanSet() {
|
||||||
|
v.Set(reflect.New(v.Type().Elem()))
|
||||||
|
} else {
|
||||||
|
v = reflect.New(v.Type().Elem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v.Type().NumMethod() > 0 {
|
||||||
|
if u, ok := v.Interface().(json.Unmarshaler); ok {
|
||||||
|
return u, nil, reflect.Value{}
|
||||||
|
}
|
||||||
|
if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
|
||||||
|
return nil, u, reflect.Value{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
return nil, nil, v
|
||||||
|
}
|
||||||
|
|
||||||
|
// A field represents a single field found in a struct.
|
||||||
|
type field struct {
|
||||||
|
name string
|
||||||
|
nameBytes []byte // []byte(name)
|
||||||
|
equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent
|
||||||
|
|
||||||
|
tag bool
|
||||||
|
index []int
|
||||||
|
typ reflect.Type
|
||||||
|
omitEmpty bool
|
||||||
|
quoted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillField(f field) field {
|
||||||
|
f.nameBytes = []byte(f.name)
|
||||||
|
f.equalFold = foldFunc(f.nameBytes)
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// byName sorts field by name, breaking ties with depth,
|
||||||
|
// then breaking ties with "name came from json tag", then
|
||||||
|
// breaking ties with index sequence.
|
||||||
|
type byName []field
|
||||||
|
|
||||||
|
func (x byName) Len() int { return len(x) }
|
||||||
|
|
||||||
|
func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||||
|
|
||||||
|
func (x byName) Less(i, j int) bool {
|
||||||
|
if x[i].name != x[j].name {
|
||||||
|
return x[i].name < x[j].name
|
||||||
|
}
|
||||||
|
if len(x[i].index) != len(x[j].index) {
|
||||||
|
return len(x[i].index) < len(x[j].index)
|
||||||
|
}
|
||||||
|
if x[i].tag != x[j].tag {
|
||||||
|
return x[i].tag
|
||||||
|
}
|
||||||
|
return byIndex(x).Less(i, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
// byIndex sorts field by index sequence.
|
||||||
|
type byIndex []field
|
||||||
|
|
||||||
|
func (x byIndex) Len() int { return len(x) }
|
||||||
|
|
||||||
|
func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||||
|
|
||||||
|
func (x byIndex) Less(i, j int) bool {
|
||||||
|
for k, xik := range x[i].index {
|
||||||
|
if k >= len(x[j].index) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if xik != x[j].index[k] {
|
||||||
|
return xik < x[j].index[k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(x[i].index) < len(x[j].index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeFields returns a list of fields that JSON should recognize for the given type.
|
||||||
|
// The algorithm is breadth-first search over the set of structs to include - the top struct
|
||||||
|
// and then any reachable anonymous structs.
|
||||||
|
func typeFields(t reflect.Type) []field {
|
||||||
|
// Anonymous fields to explore at the current level and the next.
|
||||||
|
current := []field{}
|
||||||
|
next := []field{{typ: t}}
|
||||||
|
|
||||||
|
// Count of queued names for current level and the next.
|
||||||
|
count := map[reflect.Type]int{}
|
||||||
|
nextCount := map[reflect.Type]int{}
|
||||||
|
|
||||||
|
// Types already visited at an earlier level.
|
||||||
|
visited := map[reflect.Type]bool{}
|
||||||
|
|
||||||
|
// Fields found.
|
||||||
|
var fields []field
|
||||||
|
|
||||||
|
for len(next) > 0 {
|
||||||
|
current, next = next, current[:0]
|
||||||
|
count, nextCount = nextCount, map[reflect.Type]int{}
|
||||||
|
|
||||||
|
for _, f := range current {
|
||||||
|
if visited[f.typ] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
visited[f.typ] = true
|
||||||
|
|
||||||
|
// Scan f.typ for fields to include.
|
||||||
|
for i := 0; i < f.typ.NumField(); i++ {
|
||||||
|
sf := f.typ.Field(i)
|
||||||
|
if sf.PkgPath != "" { // unexported
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tag := sf.Tag.Get("json")
|
||||||
|
if tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name, opts := parseTag(tag)
|
||||||
|
if !isValidTag(name) {
|
||||||
|
name = ""
|
||||||
|
}
|
||||||
|
index := make([]int, len(f.index)+1)
|
||||||
|
copy(index, f.index)
|
||||||
|
index[len(f.index)] = i
|
||||||
|
|
||||||
|
ft := sf.Type
|
||||||
|
if ft.Name() == "" && ft.Kind() == reflect.Ptr {
|
||||||
|
// Follow pointer.
|
||||||
|
ft = ft.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record found field and index sequence.
|
||||||
|
if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
|
||||||
|
tagged := name != ""
|
||||||
|
if name == "" {
|
||||||
|
name = sf.Name
|
||||||
|
}
|
||||||
|
fields = append(fields, fillField(field{
|
||||||
|
name: name,
|
||||||
|
tag: tagged,
|
||||||
|
index: index,
|
||||||
|
typ: ft,
|
||||||
|
omitEmpty: opts.Contains("omitempty"),
|
||||||
|
quoted: opts.Contains("string"),
|
||||||
|
}))
|
||||||
|
if count[f.typ] > 1 {
|
||||||
|
// If there were multiple instances, add a second,
|
||||||
|
// so that the annihilation code will see a duplicate.
|
||||||
|
// It only cares about the distinction between 1 or 2,
|
||||||
|
// so don't bother generating any more copies.
|
||||||
|
fields = append(fields, fields[len(fields)-1])
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record new anonymous struct to explore in next round.
|
||||||
|
nextCount[ft]++
|
||||||
|
if nextCount[ft] == 1 {
|
||||||
|
next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(byName(fields))
|
||||||
|
|
||||||
|
// Delete all fields that are hidden by the Go rules for embedded fields,
|
||||||
|
// except that fields with JSON tags are promoted.
|
||||||
|
|
||||||
|
// The fields are sorted in primary order of name, secondary order
|
||||||
|
// of field index length. Loop over names; for each name, delete
|
||||||
|
// hidden fields by choosing the one dominant field that survives.
|
||||||
|
out := fields[:0]
|
||||||
|
for advance, i := 0, 0; i < len(fields); i += advance {
|
||||||
|
// One iteration per name.
|
||||||
|
// Find the sequence of fields with the name of this first field.
|
||||||
|
fi := fields[i]
|
||||||
|
name := fi.name
|
||||||
|
for advance = 1; i+advance < len(fields); advance++ {
|
||||||
|
fj := fields[i+advance]
|
||||||
|
if fj.name != name {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if advance == 1 { // Only one field with this name
|
||||||
|
out = append(out, fi)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dominant, ok := dominantField(fields[i : i+advance])
|
||||||
|
if ok {
|
||||||
|
out = append(out, dominant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fields = out
|
||||||
|
sort.Sort(byIndex(fields))
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
// dominantField looks through the fields, all of which are known to
|
||||||
|
// have the same name, to find the single field that dominates the
|
||||||
|
// others using Go's embedding rules, modified by the presence of
|
||||||
|
// JSON tags. If there are multiple top-level fields, the boolean
|
||||||
|
// will be false: This condition is an error in Go and we skip all
|
||||||
|
// the fields.
|
||||||
|
func dominantField(fields []field) (field, bool) {
|
||||||
|
// The fields are sorted in increasing index-length order. The winner
|
||||||
|
// must therefore be one with the shortest index length. Drop all
|
||||||
|
// longer entries, which is easy: just truncate the slice.
|
||||||
|
length := len(fields[0].index)
|
||||||
|
tagged := -1 // Index of first tagged field.
|
||||||
|
for i, f := range fields {
|
||||||
|
if len(f.index) > length {
|
||||||
|
fields = fields[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if f.tag {
|
||||||
|
if tagged >= 0 {
|
||||||
|
// Multiple tagged fields at the same level: conflict.
|
||||||
|
// Return no field.
|
||||||
|
return field{}, false
|
||||||
|
}
|
||||||
|
tagged = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tagged >= 0 {
|
||||||
|
return fields[tagged], true
|
||||||
|
}
|
||||||
|
// All remaining fields have the same length. If there's more than one,
|
||||||
|
// we have a conflict (two fields named "X" at the same level) and we
|
||||||
|
// return no field.
|
||||||
|
if len(fields) > 1 {
|
||||||
|
return field{}, false
|
||||||
|
}
|
||||||
|
return fields[0], true
|
||||||
|
}
|
||||||
|
|
||||||
|
var fieldCache struct {
|
||||||
|
sync.RWMutex
|
||||||
|
m map[reflect.Type][]field
|
||||||
|
}
|
||||||
|
|
||||||
|
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
|
||||||
|
func cachedTypeFields(t reflect.Type) []field {
|
||||||
|
fieldCache.RLock()
|
||||||
|
f := fieldCache.m[t]
|
||||||
|
fieldCache.RUnlock()
|
||||||
|
if f != nil {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute fields without lock.
|
||||||
|
// Might duplicate effort but won't hold other computations back.
|
||||||
|
f = typeFields(t)
|
||||||
|
if f == nil {
|
||||||
|
f = []field{}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldCache.Lock()
|
||||||
|
if fieldCache.m == nil {
|
||||||
|
fieldCache.m = map[reflect.Type][]field{}
|
||||||
|
}
|
||||||
|
fieldCache.m[t] = f
|
||||||
|
fieldCache.Unlock()
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidTag(s string) bool {
|
||||||
|
if s == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, c := range s {
|
||||||
|
switch {
|
||||||
|
case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
|
||||||
|
// Backslash and quote chars are reserved, but
|
||||||
|
// otherwise any punctuation chars are allowed
|
||||||
|
// in a tag name.
|
||||||
|
default:
|
||||||
|
if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
caseMask = ^byte(0x20) // Mask to ignore case in ASCII.
|
||||||
|
kelvin = '\u212a'
|
||||||
|
smallLongEss = '\u017f'
|
||||||
|
)
|
||||||
|
|
||||||
|
// foldFunc returns one of four different case folding equivalence
|
||||||
|
// functions, from most general (and slow) to fastest:
|
||||||
|
//
|
||||||
|
// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
|
||||||
|
// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
|
||||||
|
// 3) asciiEqualFold, no special, but includes non-letters (including _)
|
||||||
|
// 4) simpleLetterEqualFold, no specials, no non-letters.
|
||||||
|
//
|
||||||
|
// The letters S and K are special because they map to 3 runes, not just 2:
|
||||||
|
// * S maps to s and to U+017F 'ſ' Latin small letter long s
|
||||||
|
// * k maps to K and to U+212A 'K' Kelvin sign
|
||||||
|
// See http://play.golang.org/p/tTxjOc0OGo
|
||||||
|
//
|
||||||
|
// The returned function is specialized for matching against s and
|
||||||
|
// should only be given s. It's not curried for performance reasons.
|
||||||
|
func foldFunc(s []byte) func(s, t []byte) bool {
|
||||||
|
nonLetter := false
|
||||||
|
special := false // special letter
|
||||||
|
for _, b := range s {
|
||||||
|
if b >= utf8.RuneSelf {
|
||||||
|
return bytes.EqualFold
|
||||||
|
}
|
||||||
|
upper := b & caseMask
|
||||||
|
if upper < 'A' || upper > 'Z' {
|
||||||
|
nonLetter = true
|
||||||
|
} else if upper == 'K' || upper == 'S' {
|
||||||
|
// See above for why these letters are special.
|
||||||
|
special = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if special {
|
||||||
|
return equalFoldRight
|
||||||
|
}
|
||||||
|
if nonLetter {
|
||||||
|
return asciiEqualFold
|
||||||
|
}
|
||||||
|
return simpleLetterEqualFold
|
||||||
|
}
|
||||||
|
|
||||||
|
// equalFoldRight is a specialization of bytes.EqualFold when s is
|
||||||
|
// known to be all ASCII (including punctuation), but contains an 's',
|
||||||
|
// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t.
|
||||||
|
// See comments on foldFunc.
|
||||||
|
func equalFoldRight(s, t []byte) bool {
|
||||||
|
for _, sb := range s {
|
||||||
|
if len(t) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
tb := t[0]
|
||||||
|
if tb < utf8.RuneSelf {
|
||||||
|
if sb != tb {
|
||||||
|
sbUpper := sb & caseMask
|
||||||
|
if 'A' <= sbUpper && sbUpper <= 'Z' {
|
||||||
|
if sbUpper != tb&caseMask {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t = t[1:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// sb is ASCII and t is not. t must be either kelvin
|
||||||
|
// sign or long s; sb must be s, S, k, or K.
|
||||||
|
tr, size := utf8.DecodeRune(t)
|
||||||
|
switch sb {
|
||||||
|
case 's', 'S':
|
||||||
|
if tr != smallLongEss {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case 'k', 'K':
|
||||||
|
if tr != kelvin {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
t = t[size:]
|
||||||
|
|
||||||
|
}
|
||||||
|
if len(t) > 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// asciiEqualFold is a specialization of bytes.EqualFold for use when
|
||||||
|
// s is all ASCII (but may contain non-letters) and contains no
|
||||||
|
// special-folding letters.
|
||||||
|
// See comments on foldFunc.
|
||||||
|
func asciiEqualFold(s, t []byte) bool {
|
||||||
|
if len(s) != len(t) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i, sb := range s {
|
||||||
|
tb := t[i]
|
||||||
|
if sb == tb {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') {
|
||||||
|
if sb&caseMask != tb&caseMask {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// simpleLetterEqualFold is a specialization of bytes.EqualFold for
|
||||||
|
// use when s is all ASCII letters (no underscores, etc) and also
|
||||||
|
// doesn't contain 'k', 'K', 's', or 'S'.
|
||||||
|
// See comments on foldFunc.
|
||||||
|
func simpleLetterEqualFold(s, t []byte) bool {
|
||||||
|
if len(s) != len(t) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i, b := range s {
|
||||||
|
if b&caseMask != t[i]&caseMask {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// tagOptions is the string following a comma in a struct field's "json"
|
||||||
|
// tag, or the empty string. It does not include the leading comma.
|
||||||
|
type tagOptions string
|
||||||
|
|
||||||
|
// parseTag splits a struct field's json tag into its name and
|
||||||
|
// comma-separated options.
|
||||||
|
func parseTag(tag string) (string, tagOptions) {
|
||||||
|
if idx := strings.Index(tag, ","); idx != -1 {
|
||||||
|
return tag[:idx], tagOptions(tag[idx+1:])
|
||||||
|
}
|
||||||
|
return tag, tagOptions("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains reports whether a comma-separated list of options
|
||||||
|
// contains a particular substr flag. substr must be surrounded by a
|
||||||
|
// string boundary or commas.
|
||||||
|
func (o tagOptions) Contains(optionName string) bool {
|
||||||
|
if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
s := string(o)
|
||||||
|
for s != "" {
|
||||||
|
var next string
|
||||||
|
i := strings.Index(s, ",")
|
||||||
|
if i >= 0 {
|
||||||
|
s, next = s[:i], s[i+1:]
|
||||||
|
}
|
||||||
|
if s == optionName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
s = next
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
|
@ -0,0 +1,277 @@
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Marshals the object into JSON then converts JSON to YAML and returns the
|
||||||
|
// YAML.
|
||||||
|
func Marshal(o interface{}) ([]byte, error) {
|
||||||
|
j, err := json.Marshal(o)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error marshaling into JSON: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
y, err := JSONToYAML(j)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error converting JSON to YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return y, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts YAML to JSON then uses JSON to unmarshal into an object.
|
||||||
|
func Unmarshal(y []byte, o interface{}) error {
|
||||||
|
vo := reflect.ValueOf(o)
|
||||||
|
j, err := yamlToJSON(y, &vo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error converting YAML to JSON: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(j, o)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error unmarshaling JSON: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert JSON to YAML.
|
||||||
|
func JSONToYAML(j []byte) ([]byte, error) {
|
||||||
|
// Convert the JSON to an object.
|
||||||
|
var jsonObj interface{}
|
||||||
|
// We are using yaml.Unmarshal here (instead of json.Unmarshal) because the
|
||||||
|
// Go JSON library doesn't try to pick the right number type (int, float,
|
||||||
|
// etc.) when unmarshalling to interface{}, it just picks float64
|
||||||
|
// universally. go-yaml does go through the effort of picking the right
|
||||||
|
// number type, so we can preserve number type throughout this process.
|
||||||
|
err := yaml.Unmarshal(j, &jsonObj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal this object into YAML.
|
||||||
|
return yaml.Marshal(jsonObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert YAML to JSON. Since JSON is a subset of YAML, passing JSON through
|
||||||
|
// this method should be a no-op.
|
||||||
|
//
|
||||||
|
// Things YAML can do that are not supported by JSON:
|
||||||
|
// * In YAML you can have binary and null keys in your maps. These are invalid
|
||||||
|
// in JSON. (int and float keys are converted to strings.)
|
||||||
|
// * Binary data in YAML with the !!binary tag is not supported. If you want to
|
||||||
|
// use binary data with this library, encode the data as base64 as usual but do
|
||||||
|
// not use the !!binary tag in your YAML. This will ensure the original base64
|
||||||
|
// encoded data makes it all the way through to the JSON.
|
||||||
|
func YAMLToJSON(y []byte) ([]byte, error) {
|
||||||
|
return yamlToJSON(y, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func yamlToJSON(y []byte, jsonTarget *reflect.Value) ([]byte, error) {
|
||||||
|
// Convert the YAML to an object.
|
||||||
|
var yamlObj interface{}
|
||||||
|
err := yaml.Unmarshal(y, &yamlObj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// YAML objects are not completely compatible with JSON objects (e.g. you
|
||||||
|
// can have non-string keys in YAML). So, convert the YAML-compatible object
|
||||||
|
// to a JSON-compatible object, failing with an error if irrecoverable
|
||||||
|
// incompatibilties happen along the way.
|
||||||
|
jsonObj, err := convertToJSONableObject(yamlObj, jsonTarget)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert this object to JSON and return the data.
|
||||||
|
return json.Marshal(jsonObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (interface{}, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Resolve jsonTarget to a concrete value (i.e. not a pointer or an
|
||||||
|
// interface). We pass decodingNull as false because we're not actually
|
||||||
|
// decoding into the value, we're just checking if the ultimate target is a
|
||||||
|
// string.
|
||||||
|
if jsonTarget != nil {
|
||||||
|
ju, tu, pv := indirect(*jsonTarget, false)
|
||||||
|
// We have a JSON or Text Umarshaler at this level, so we can't be trying
|
||||||
|
// to decode into a string.
|
||||||
|
if ju != nil || tu != nil {
|
||||||
|
jsonTarget = nil
|
||||||
|
} else {
|
||||||
|
jsonTarget = &pv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If yamlObj is a number or a boolean, check if jsonTarget is a string -
|
||||||
|
// if so, coerce. Else return normal.
|
||||||
|
// If yamlObj is a map or array, find the field that each key is
|
||||||
|
// unmarshaling to, and when you recurse pass the reflect.Value for that
|
||||||
|
// field back into this function.
|
||||||
|
switch typedYAMLObj := yamlObj.(type) {
|
||||||
|
case map[interface{}]interface{}:
|
||||||
|
// JSON does not support arbitrary keys in a map, so we must convert
|
||||||
|
// these keys to strings.
|
||||||
|
//
|
||||||
|
// From my reading of go-yaml v2 (specifically the resolve function),
|
||||||
|
// keys can only have the types string, int, int64, float64, binary
|
||||||
|
// (unsupported), or null (unsupported).
|
||||||
|
strMap := make(map[string]interface{})
|
||||||
|
for k, v := range typedYAMLObj {
|
||||||
|
// Resolve the key to a string first.
|
||||||
|
var keyString string
|
||||||
|
switch typedKey := k.(type) {
|
||||||
|
case string:
|
||||||
|
keyString = typedKey
|
||||||
|
case int:
|
||||||
|
keyString = strconv.Itoa(typedKey)
|
||||||
|
case int64:
|
||||||
|
// go-yaml will only return an int64 as a key if the system
|
||||||
|
// architecture is 32-bit and the key's value is between 32-bit
|
||||||
|
// and 64-bit. Otherwise the key type will simply be int.
|
||||||
|
keyString = strconv.FormatInt(typedKey, 10)
|
||||||
|
case float64:
|
||||||
|
// Stolen from go-yaml to use the same conversion to string as
|
||||||
|
// the go-yaml library uses to convert float to string when
|
||||||
|
// Marshaling.
|
||||||
|
s := strconv.FormatFloat(typedKey, 'g', -1, 32)
|
||||||
|
switch s {
|
||||||
|
case "+Inf":
|
||||||
|
s = ".inf"
|
||||||
|
case "-Inf":
|
||||||
|
s = "-.inf"
|
||||||
|
case "NaN":
|
||||||
|
s = ".nan"
|
||||||
|
}
|
||||||
|
keyString = s
|
||||||
|
case bool:
|
||||||
|
if typedKey {
|
||||||
|
keyString = "true"
|
||||||
|
} else {
|
||||||
|
keyString = "false"
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Unsupported map key of type: %s, key: %+#v, value: %+#v",
|
||||||
|
reflect.TypeOf(k), k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// jsonTarget should be a struct or a map. If it's a struct, find
|
||||||
|
// the field it's going to map to and pass its reflect.Value. If
|
||||||
|
// it's a map, find the element type of the map and pass the
|
||||||
|
// reflect.Value created from that type. If it's neither, just pass
|
||||||
|
// nil - JSON conversion will error for us if it's a real issue.
|
||||||
|
if jsonTarget != nil {
|
||||||
|
t := *jsonTarget
|
||||||
|
if t.Kind() == reflect.Struct {
|
||||||
|
keyBytes := []byte(keyString)
|
||||||
|
// Find the field that the JSON library would use.
|
||||||
|
var f *field
|
||||||
|
fields := cachedTypeFields(t.Type())
|
||||||
|
for i := range fields {
|
||||||
|
ff := &fields[i]
|
||||||
|
if bytes.Equal(ff.nameBytes, keyBytes) {
|
||||||
|
f = ff
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Do case-insensitive comparison.
|
||||||
|
if f == nil && ff.equalFold(ff.nameBytes, keyBytes) {
|
||||||
|
f = ff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if f != nil {
|
||||||
|
// Find the reflect.Value of the most preferential
|
||||||
|
// struct field.
|
||||||
|
jtf := t.Field(f.index[0])
|
||||||
|
strMap[keyString], err = convertToJSONableObject(v, &jtf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if t.Kind() == reflect.Map {
|
||||||
|
// Create a zero value of the map's element type to use as
|
||||||
|
// the JSON target.
|
||||||
|
jtv := reflect.Zero(t.Type().Elem())
|
||||||
|
strMap[keyString], err = convertToJSONableObject(v, &jtv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strMap[keyString], err = convertToJSONableObject(v, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strMap, nil
|
||||||
|
case []interface{}:
|
||||||
|
// We need to recurse into arrays in case there are any
|
||||||
|
// map[interface{}]interface{}'s inside and to convert any
|
||||||
|
// numbers to strings.
|
||||||
|
|
||||||
|
// If jsonTarget is a slice (which it really should be), find the
|
||||||
|
// thing it's going to map to. If it's not a slice, just pass nil
|
||||||
|
// - JSON conversion will error for us if it's a real issue.
|
||||||
|
var jsonSliceElemValue *reflect.Value
|
||||||
|
if jsonTarget != nil {
|
||||||
|
t := *jsonTarget
|
||||||
|
if t.Kind() == reflect.Slice {
|
||||||
|
// By default slices point to nil, but we need a reflect.Value
|
||||||
|
// pointing to a value of the slice type, so we create one here.
|
||||||
|
ev := reflect.Indirect(reflect.New(t.Type().Elem()))
|
||||||
|
jsonSliceElemValue = &ev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make and use a new array.
|
||||||
|
arr := make([]interface{}, len(typedYAMLObj))
|
||||||
|
for i, v := range typedYAMLObj {
|
||||||
|
arr[i], err = convertToJSONableObject(v, jsonSliceElemValue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr, nil
|
||||||
|
default:
|
||||||
|
// If the target type is a string and the YAML type is a number,
|
||||||
|
// convert the YAML type to a string.
|
||||||
|
if jsonTarget != nil && (*jsonTarget).Kind() == reflect.String {
|
||||||
|
// Based on my reading of go-yaml, it may return int, int64,
|
||||||
|
// float64, or uint64.
|
||||||
|
var s string
|
||||||
|
switch typedVal := typedYAMLObj.(type) {
|
||||||
|
case int:
|
||||||
|
s = strconv.FormatInt(int64(typedVal), 10)
|
||||||
|
case int64:
|
||||||
|
s = strconv.FormatInt(typedVal, 10)
|
||||||
|
case float64:
|
||||||
|
s = strconv.FormatFloat(typedVal, 'g', -1, 32)
|
||||||
|
case uint64:
|
||||||
|
s = strconv.FormatUint(typedVal, 10)
|
||||||
|
case bool:
|
||||||
|
if typedVal {
|
||||||
|
s = "true"
|
||||||
|
} else {
|
||||||
|
s = "false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(s) > 0 {
|
||||||
|
yamlObj = interface{}(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return yamlObj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
|
@ -24,8 +24,9 @@ import (
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// dialect := gorp.MySQLDialect{"InnoDB", "UTF8"}
|
// dialect := gorp.MySQLDialect{"InnoDB", "UTF8"}
|
||||||
// dbmap := &gorp.DbMap{Db: db, Dialect: dialect}
|
// dbmap := &gorp.DbMap{Db: db, Dialect: dialect}
|
||||||
|
//
|
||||||
type DbMap struct {
|
type DbMap struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
||||||
|
|
|
@ -5,148 +5,148 @@
|
||||||
package gorp
|
package gorp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SnowflakeDialect struct {
|
type SnowflakeDialect struct {
|
||||||
suffix string
|
suffix string
|
||||||
LowercaseFields bool
|
LowercaseFields bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) QuerySuffix() string { return ";" }
|
func (d SnowflakeDialect) QuerySuffix() string { return ";" }
|
||||||
|
|
||||||
func (d SnowflakeDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
|
func (d SnowflakeDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
|
||||||
switch val.Kind() {
|
switch val.Kind() {
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
|
return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return "boolean"
|
return "boolean"
|
||||||
case reflect.Int,
|
case reflect.Int,
|
||||||
reflect.Int8,
|
reflect.Int8,
|
||||||
reflect.Int16,
|
reflect.Int16,
|
||||||
reflect.Int32,
|
reflect.Int32,
|
||||||
reflect.Uint,
|
reflect.Uint,
|
||||||
reflect.Uint8,
|
reflect.Uint8,
|
||||||
reflect.Uint16,
|
reflect.Uint16,
|
||||||
reflect.Uint32:
|
reflect.Uint32:
|
||||||
|
|
||||||
if isAutoIncr {
|
if isAutoIncr {
|
||||||
return "serial"
|
return "serial"
|
||||||
}
|
}
|
||||||
return "integer"
|
return "integer"
|
||||||
case reflect.Int64, reflect.Uint64:
|
case reflect.Int64, reflect.Uint64:
|
||||||
if isAutoIncr {
|
if isAutoIncr {
|
||||||
return "bigserial"
|
return "bigserial"
|
||||||
}
|
}
|
||||||
return "bigint"
|
return "bigint"
|
||||||
case reflect.Float64:
|
case reflect.Float64:
|
||||||
return "double precision"
|
return "double precision"
|
||||||
case reflect.Float32:
|
case reflect.Float32:
|
||||||
return "real"
|
return "real"
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
if val.Elem().Kind() == reflect.Uint8 {
|
if val.Elem().Kind() == reflect.Uint8 {
|
||||||
return "binary"
|
return "binary"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch val.Name() {
|
switch val.Name() {
|
||||||
case "NullInt64":
|
case "NullInt64":
|
||||||
return "bigint"
|
return "bigint"
|
||||||
case "NullFloat64":
|
case "NullFloat64":
|
||||||
return "double precision"
|
return "double precision"
|
||||||
case "NullBool":
|
case "NullBool":
|
||||||
return "boolean"
|
return "boolean"
|
||||||
case "Time", "NullTime":
|
case "Time", "NullTime":
|
||||||
return "timestamp with time zone"
|
return "timestamp with time zone"
|
||||||
}
|
}
|
||||||
|
|
||||||
if maxsize > 0 {
|
if maxsize > 0 {
|
||||||
return fmt.Sprintf("varchar(%d)", maxsize)
|
return fmt.Sprintf("varchar(%d)", maxsize)
|
||||||
} else {
|
} else {
|
||||||
return "text"
|
return "text"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns empty string
|
// Returns empty string
|
||||||
func (d SnowflakeDialect) AutoIncrStr() string {
|
func (d SnowflakeDialect) AutoIncrStr() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) AutoIncrBindValue() string {
|
func (d SnowflakeDialect) AutoIncrBindValue() string {
|
||||||
return "default"
|
return "default"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
|
func (d SnowflakeDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns suffix
|
// Returns suffix
|
||||||
func (d SnowflakeDialect) CreateTableSuffix() string {
|
func (d SnowflakeDialect) CreateTableSuffix() string {
|
||||||
return d.suffix
|
return d.suffix
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) CreateIndexSuffix() string {
|
func (d SnowflakeDialect) CreateIndexSuffix() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) DropIndexSuffix() string {
|
func (d SnowflakeDialect) DropIndexSuffix() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) TruncateClause() string {
|
func (d SnowflakeDialect) TruncateClause() string {
|
||||||
return "truncate"
|
return "truncate"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns "$(i+1)"
|
// Returns "$(i+1)"
|
||||||
func (d SnowflakeDialect) BindVar(i int) string {
|
func (d SnowflakeDialect) BindVar(i int) string {
|
||||||
return "?"
|
return "?"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) InsertAutoIncrToTarget(exec SqlExecutor, insertSql string, target interface{}, params ...interface{}) error {
|
func (d SnowflakeDialect) InsertAutoIncrToTarget(exec SqlExecutor, insertSql string, target interface{}, params ...interface{}) error {
|
||||||
rows, err := exec.Query(insertSql, params...)
|
rows, err := exec.Query(insertSql, params...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
if !rows.Next() {
|
if !rows.Next() {
|
||||||
return fmt.Errorf("No serial value returned for insert: %s Encountered error: %s", insertSql, rows.Err())
|
return fmt.Errorf("No serial value returned for insert: %s Encountered error: %s", insertSql, rows.Err())
|
||||||
}
|
}
|
||||||
if err := rows.Scan(target); err != nil {
|
if err := rows.Scan(target); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if rows.Next() {
|
if rows.Next() {
|
||||||
return fmt.Errorf("more than two serial value returned for insert: %s", insertSql)
|
return fmt.Errorf("more than two serial value returned for insert: %s", insertSql)
|
||||||
}
|
}
|
||||||
return rows.Err()
|
return rows.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) QuoteField(f string) string {
|
func (d SnowflakeDialect) QuoteField(f string) string {
|
||||||
if d.LowercaseFields {
|
if d.LowercaseFields {
|
||||||
return `"` + strings.ToLower(f) + `"`
|
return `"` + strings.ToLower(f) + `"`
|
||||||
}
|
}
|
||||||
return `"` + f + `"`
|
return `"` + f + `"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) QuotedTableForQuery(schema string, table string) string {
|
func (d SnowflakeDialect) QuotedTableForQuery(schema string, table string) string {
|
||||||
if strings.TrimSpace(schema) == "" {
|
if strings.TrimSpace(schema) == "" {
|
||||||
return d.QuoteField(table)
|
return d.QuoteField(table)
|
||||||
}
|
}
|
||||||
|
|
||||||
return schema + "." + d.QuoteField(table)
|
return schema + "." + d.QuoteField(table)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) IfSchemaNotExists(command, schema string) string {
|
func (d SnowflakeDialect) IfSchemaNotExists(command, schema string) string {
|
||||||
return fmt.Sprintf("%s if not exists", command)
|
return fmt.Sprintf("%s if not exists", command)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) IfTableExists(command, schema, table string) string {
|
func (d SnowflakeDialect) IfTableExists(command, schema, table string) string {
|
||||||
return fmt.Sprintf("%s if exists", command)
|
return fmt.Sprintf("%s if exists", command)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SnowflakeDialect) IfTableNotExists(command, schema, table string) string {
|
func (d SnowflakeDialect) IfTableNotExists(command, schema, table string) string {
|
||||||
return fmt.Sprintf("%s if not exists", command)
|
return fmt.Sprintf("%s if not exists", command)
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,9 +86,10 @@ func SelectNullStr(e SqlExecutor, query string, args ...interface{}) (sql.NullSt
|
||||||
// SelectOne executes the given query (which should be a SELECT statement)
|
// SelectOne executes the given query (which should be a SELECT statement)
|
||||||
// and binds the result to holder, which must be a pointer.
|
// and binds the result to holder, which must be a pointer.
|
||||||
//
|
//
|
||||||
// # If no row is found, an error (sql.ErrNoRows specifically) will be returned
|
// If no row is found, an error (sql.ErrNoRows specifically) will be returned
|
||||||
//
|
//
|
||||||
// If more than one row is found, an error will be returned.
|
// If more than one row is found, an error will be returned.
|
||||||
|
//
|
||||||
func SelectOne(m *DbMap, e SqlExecutor, holder interface{}, query string, args ...interface{}) error {
|
func SelectOne(m *DbMap, e SqlExecutor, holder interface{}, query string, args ...interface{}) error {
|
||||||
t := reflect.TypeOf(holder)
|
t := reflect.TypeOf(holder)
|
||||||
if t.Kind() == reflect.Ptr {
|
if t.Kind() == reflect.Ptr {
|
||||||
|
|
|
@ -47,6 +47,7 @@ func (t *TableMap) ResetSql() {
|
||||||
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
|
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
|
||||||
//
|
//
|
||||||
// Panics if isAutoIncr is true, and fieldNames length != 1
|
// Panics if isAutoIncr is true, and fieldNames length != 1
|
||||||
|
//
|
||||||
func (t *TableMap) SetKeys(isAutoIncr bool, fieldNames ...string) *TableMap {
|
func (t *TableMap) SetKeys(isAutoIncr bool, fieldNames ...string) *TableMap {
|
||||||
if isAutoIncr && len(fieldNames) != 1 {
|
if isAutoIncr && len(fieldNames) != 1 {
|
||||||
panic(fmt.Sprintf(
|
panic(fmt.Sprintf(
|
||||||
|
@ -72,6 +73,7 @@ func (t *TableMap) SetKeys(isAutoIncr bool, fieldNames ...string) *TableMap {
|
||||||
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
|
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
|
||||||
//
|
//
|
||||||
// Panics if fieldNames length < 2.
|
// Panics if fieldNames length < 2.
|
||||||
|
//
|
||||||
func (t *TableMap) SetUniqueTogether(fieldNames ...string) *TableMap {
|
func (t *TableMap) SetUniqueTogether(fieldNames ...string) *TableMap {
|
||||||
if len(fieldNames) < 2 {
|
if len(fieldNames) < 2 {
|
||||||
panic(fmt.Sprintf(
|
panic(fmt.Sprintf(
|
||||||
|
@ -133,6 +135,7 @@ func (t *TableMap) IdxMap(field string) *IndexMap {
|
||||||
// Function will panic if one of the given for index columns does not exists
|
// Function will panic if one of the given for index columns does not exists
|
||||||
//
|
//
|
||||||
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
|
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
|
||||||
|
//
|
||||||
func (t *TableMap) AddIndex(name string, idxtype string, columns []string) *IndexMap {
|
func (t *TableMap) AddIndex(name string, idxtype string, columns []string) *IndexMap {
|
||||||
// check if we have a index with this name already
|
// check if we have a index with this name already
|
||||||
for _, idx := range t.indexes {
|
for _, idx := range t.indexes {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Unix-style newlines with a newline ending every file
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# Set default charset
|
||||||
|
[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
|
||||||
|
charset = utf-8
|
||||||
|
|
||||||
|
# Tab indentation (no size specified)
|
||||||
|
[*.go]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
# Matches the exact files either package.json or .travis.yml
|
||||||
|
[{package.json,.travis.yml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
|
@ -0,0 +1 @@
|
||||||
|
secrets.yml
|
|
@ -0,0 +1,61 @@
|
||||||
|
linters-settings:
|
||||||
|
govet:
|
||||||
|
check-shadowing: true
|
||||||
|
golint:
|
||||||
|
min-confidence: 0
|
||||||
|
gocyclo:
|
||||||
|
min-complexity: 45
|
||||||
|
maligned:
|
||||||
|
suggest-new: true
|
||||||
|
dupl:
|
||||||
|
threshold: 200
|
||||||
|
goconst:
|
||||||
|
min-len: 2
|
||||||
|
min-occurrences: 3
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable-all: true
|
||||||
|
disable:
|
||||||
|
- maligned
|
||||||
|
- unparam
|
||||||
|
- lll
|
||||||
|
- gochecknoinits
|
||||||
|
- gochecknoglobals
|
||||||
|
- funlen
|
||||||
|
- godox
|
||||||
|
- gocognit
|
||||||
|
- whitespace
|
||||||
|
- wsl
|
||||||
|
- wrapcheck
|
||||||
|
- testpackage
|
||||||
|
- nlreturn
|
||||||
|
- gomnd
|
||||||
|
- exhaustivestruct
|
||||||
|
- goerr113
|
||||||
|
- errorlint
|
||||||
|
- nestif
|
||||||
|
- godot
|
||||||
|
- gofumpt
|
||||||
|
- paralleltest
|
||||||
|
- tparallel
|
||||||
|
- thelper
|
||||||
|
- ifshort
|
||||||
|
- exhaustruct
|
||||||
|
- varnamelen
|
||||||
|
- gci
|
||||||
|
- depguard
|
||||||
|
- errchkjson
|
||||||
|
- inamedparam
|
||||||
|
- nonamedreturns
|
||||||
|
- musttag
|
||||||
|
- ireturn
|
||||||
|
- forcetypeassert
|
||||||
|
- cyclop
|
||||||
|
# deprecated linters
|
||||||
|
- deadcode
|
||||||
|
- interfacer
|
||||||
|
- scopelint
|
||||||
|
- varcheck
|
||||||
|
- structcheck
|
||||||
|
- golint
|
||||||
|
- nosnakecase
|
|
@ -0,0 +1,74 @@
|
||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In 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.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment
|
||||||
|
include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
|
advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic
|
||||||
|
address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project 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.
|
||||||
|
|
||||||
|
Project 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.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This 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.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by contacting the project team at ivan+abuse@flanders.co.nz. All
|
||||||
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
|
is deemed necessary and 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.
|
||||||
|
|
||||||
|
Project 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.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at [http://contributor-covenant.org/version/1/4][version]
|
||||||
|
|
||||||
|
[homepage]: http://contributor-covenant.org
|
||||||
|
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -0,0 +1,19 @@
|
||||||
|
# gojsonpointer [![Build Status](https://github.com/go-openapi/jsonpointer/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/jsonpointer/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonpointer)
|
||||||
|
|
||||||
|
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
|
||||||
|
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE)
|
||||||
|
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/jsonpointer.svg)](https://pkg.go.dev/github.com/go-openapi/jsonpointer)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/jsonpointer)](https://goreportcard.com/report/github.com/go-openapi/jsonpointer)
|
||||||
|
|
||||||
|
An implementation of JSON Pointer - Go language
|
||||||
|
|
||||||
|
## Status
|
||||||
|
Completed YES
|
||||||
|
|
||||||
|
Tested YES
|
||||||
|
|
||||||
|
## References
|
||||||
|
http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
|
||||||
|
|
||||||
|
### Note
|
||||||
|
The 4.Evaluation part of the previous reference, starting with 'If the currently referenced value is a JSON array, the reference token MUST contain either...' is not implemented.
|
|
@ -0,0 +1,531 @@
|
||||||
|
// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// author sigu-399
|
||||||
|
// author-github https://github.com/sigu-399
|
||||||
|
// author-mail sigu.399@gmail.com
|
||||||
|
//
|
||||||
|
// repository-name jsonpointer
|
||||||
|
// repository-desc An implementation of JSON Pointer - Go language
|
||||||
|
//
|
||||||
|
// description Main and unique file.
|
||||||
|
//
|
||||||
|
// created 25-02-2013
|
||||||
|
|
||||||
|
package jsonpointer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
emptyPointer = ``
|
||||||
|
pointerSeparator = `/`
|
||||||
|
|
||||||
|
invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator
|
||||||
|
notFound = `Can't find the pointer in the document`
|
||||||
|
)
|
||||||
|
|
||||||
|
var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
|
||||||
|
var jsonSetableType = reflect.TypeOf(new(JSONSetable)).Elem()
|
||||||
|
|
||||||
|
// JSONPointable is an interface for structs to implement when they need to customize the
|
||||||
|
// json pointer process
|
||||||
|
type JSONPointable interface {
|
||||||
|
JSONLookup(string) (any, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONSetable is an interface for structs to implement when they need to customize the
|
||||||
|
// json pointer process
|
||||||
|
type JSONSetable interface {
|
||||||
|
JSONSet(string, any) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new json pointer for the given string
|
||||||
|
func New(jsonPointerString string) (Pointer, error) {
|
||||||
|
|
||||||
|
var p Pointer
|
||||||
|
err := p.parse(jsonPointerString)
|
||||||
|
return p, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer the json pointer reprsentation
|
||||||
|
type Pointer struct {
|
||||||
|
referenceTokens []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Constructor", parses the given string JSON pointer
|
||||||
|
func (p *Pointer) parse(jsonPointerString string) error {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if jsonPointerString != emptyPointer {
|
||||||
|
if !strings.HasPrefix(jsonPointerString, pointerSeparator) {
|
||||||
|
err = errors.New(invalidStart)
|
||||||
|
} else {
|
||||||
|
referenceTokens := strings.Split(jsonPointerString, pointerSeparator)
|
||||||
|
p.referenceTokens = append(p.referenceTokens, referenceTokens[1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get uses the pointer to retrieve a value from a JSON document
|
||||||
|
func (p *Pointer) Get(document any) (any, reflect.Kind, error) {
|
||||||
|
return p.get(document, swag.DefaultJSONNameProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set uses the pointer to set a value from a JSON document
|
||||||
|
func (p *Pointer) Set(document any, value any) (any, error) {
|
||||||
|
return document, p.set(document, value, swag.DefaultJSONNameProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetForToken gets a value for a json pointer token 1 level deep
|
||||||
|
func GetForToken(document any, decodedToken string) (any, reflect.Kind, error) {
|
||||||
|
return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetForToken gets a value for a json pointer token 1 level deep
|
||||||
|
func SetForToken(document any, decodedToken string, value any) (any, error) {
|
||||||
|
return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNil(input any) bool {
|
||||||
|
if input == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
kind := reflect.TypeOf(input).Kind()
|
||||||
|
switch kind { //nolint:exhaustive
|
||||||
|
case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
|
||||||
|
return reflect.ValueOf(input).IsNil()
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
|
||||||
|
rValue := reflect.Indirect(reflect.ValueOf(node))
|
||||||
|
kind := rValue.Kind()
|
||||||
|
if isNil(node) {
|
||||||
|
return nil, kind, fmt.Errorf("nil value has not field %q", decodedToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typed := node.(type) {
|
||||||
|
case JSONPointable:
|
||||||
|
r, err := typed.JSONLookup(decodedToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, kind, err
|
||||||
|
}
|
||||||
|
return r, kind, nil
|
||||||
|
case *any: // case of a pointer to interface, that is not resolved by reflect.Indirect
|
||||||
|
return getSingleImpl(*typed, decodedToken, nameProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch kind { //nolint:exhaustive
|
||||||
|
case reflect.Struct:
|
||||||
|
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
|
||||||
|
if !ok {
|
||||||
|
return nil, kind, fmt.Errorf("object has no field %q", decodedToken)
|
||||||
|
}
|
||||||
|
fld := rValue.FieldByName(nm)
|
||||||
|
return fld.Interface(), kind, nil
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
kv := reflect.ValueOf(decodedToken)
|
||||||
|
mv := rValue.MapIndex(kv)
|
||||||
|
|
||||||
|
if mv.IsValid() {
|
||||||
|
return mv.Interface(), kind, nil
|
||||||
|
}
|
||||||
|
return nil, kind, fmt.Errorf("object has no key %q", decodedToken)
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
tokenIndex, err := strconv.Atoi(decodedToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, kind, err
|
||||||
|
}
|
||||||
|
sLength := rValue.Len()
|
||||||
|
if tokenIndex < 0 || tokenIndex >= sLength {
|
||||||
|
return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength-1, tokenIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
elem := rValue.Index(tokenIndex)
|
||||||
|
return elem.Interface(), kind, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, kind, fmt.Errorf("invalid token reference %q", decodedToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameProvider) error {
|
||||||
|
rValue := reflect.Indirect(reflect.ValueOf(node))
|
||||||
|
|
||||||
|
if ns, ok := node.(JSONSetable); ok { // pointer impl
|
||||||
|
return ns.JSONSet(decodedToken, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rValue.Type().Implements(jsonSetableType) {
|
||||||
|
return node.(JSONSetable).JSONSet(decodedToken, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch rValue.Kind() { //nolint:exhaustive
|
||||||
|
case reflect.Struct:
|
||||||
|
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("object has no field %q", decodedToken)
|
||||||
|
}
|
||||||
|
fld := rValue.FieldByName(nm)
|
||||||
|
if fld.IsValid() {
|
||||||
|
fld.Set(reflect.ValueOf(data))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
kv := reflect.ValueOf(decodedToken)
|
||||||
|
rValue.SetMapIndex(kv, reflect.ValueOf(data))
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
tokenIndex, err := strconv.Atoi(decodedToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sLength := rValue.Len()
|
||||||
|
if tokenIndex < 0 || tokenIndex >= sLength {
|
||||||
|
return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
elem := rValue.Index(tokenIndex)
|
||||||
|
if !elem.CanSet() {
|
||||||
|
return fmt.Errorf("can't set slice index %s to %v", decodedToken, data)
|
||||||
|
}
|
||||||
|
elem.Set(reflect.ValueOf(data))
|
||||||
|
return nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid token reference %q", decodedToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pointer) get(node any, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
|
||||||
|
|
||||||
|
if nameProvider == nil {
|
||||||
|
nameProvider = swag.DefaultJSONNameProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
kind := reflect.Invalid
|
||||||
|
|
||||||
|
// Full document when empty
|
||||||
|
if len(p.referenceTokens) == 0 {
|
||||||
|
return node, kind, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, token := range p.referenceTokens {
|
||||||
|
|
||||||
|
decodedToken := Unescape(token)
|
||||||
|
|
||||||
|
r, knd, err := getSingleImpl(node, decodedToken, nameProvider)
|
||||||
|
if err != nil {
|
||||||
|
return nil, knd, err
|
||||||
|
}
|
||||||
|
node = r
|
||||||
|
}
|
||||||
|
|
||||||
|
rValue := reflect.ValueOf(node)
|
||||||
|
kind = rValue.Kind()
|
||||||
|
|
||||||
|
return node, kind, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error {
|
||||||
|
knd := reflect.ValueOf(node).Kind()
|
||||||
|
|
||||||
|
if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
|
||||||
|
return errors.New("only structs, pointers, maps and slices are supported for setting values")
|
||||||
|
}
|
||||||
|
|
||||||
|
if nameProvider == nil {
|
||||||
|
nameProvider = swag.DefaultJSONNameProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full document when empty
|
||||||
|
if len(p.referenceTokens) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
lastI := len(p.referenceTokens) - 1
|
||||||
|
for i, token := range p.referenceTokens {
|
||||||
|
isLastToken := i == lastI
|
||||||
|
decodedToken := Unescape(token)
|
||||||
|
|
||||||
|
if isLastToken {
|
||||||
|
|
||||||
|
return setSingleImpl(node, data, decodedToken, nameProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
rValue := reflect.Indirect(reflect.ValueOf(node))
|
||||||
|
kind := rValue.Kind()
|
||||||
|
|
||||||
|
if rValue.Type().Implements(jsonPointableType) {
|
||||||
|
r, err := node.(JSONPointable).JSONLookup(decodedToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fld := reflect.ValueOf(r)
|
||||||
|
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
|
||||||
|
node = fld.Addr().Interface()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node = r
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch kind { //nolint:exhaustive
|
||||||
|
case reflect.Struct:
|
||||||
|
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("object has no field %q", decodedToken)
|
||||||
|
}
|
||||||
|
fld := rValue.FieldByName(nm)
|
||||||
|
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
|
||||||
|
node = fld.Addr().Interface()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node = fld.Interface()
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
kv := reflect.ValueOf(decodedToken)
|
||||||
|
mv := rValue.MapIndex(kv)
|
||||||
|
|
||||||
|
if !mv.IsValid() {
|
||||||
|
return fmt.Errorf("object has no key %q", decodedToken)
|
||||||
|
}
|
||||||
|
if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Ptr {
|
||||||
|
node = mv.Addr().Interface()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node = mv.Interface()
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
tokenIndex, err := strconv.Atoi(decodedToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sLength := rValue.Len()
|
||||||
|
if tokenIndex < 0 || tokenIndex >= sLength {
|
||||||
|
return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
elem := rValue.Index(tokenIndex)
|
||||||
|
if elem.CanAddr() && elem.Kind() != reflect.Interface && elem.Kind() != reflect.Map && elem.Kind() != reflect.Slice && elem.Kind() != reflect.Ptr {
|
||||||
|
node = elem.Addr().Interface()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node = elem.Interface()
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid token reference %q", decodedToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodedTokens returns the decoded tokens
|
||||||
|
func (p *Pointer) DecodedTokens() []string {
|
||||||
|
result := make([]string, 0, len(p.referenceTokens))
|
||||||
|
for _, t := range p.referenceTokens {
|
||||||
|
result = append(result, Unescape(t))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns true if this is an empty json pointer
|
||||||
|
// this indicates that it points to the root document
|
||||||
|
func (p *Pointer) IsEmpty() bool {
|
||||||
|
return len(p.referenceTokens) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer to string representation function
|
||||||
|
func (p *Pointer) String() string {
|
||||||
|
|
||||||
|
if len(p.referenceTokens) == 0 {
|
||||||
|
return emptyPointer
|
||||||
|
}
|
||||||
|
|
||||||
|
pointerString := pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
|
||||||
|
|
||||||
|
return pointerString
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pointer) Offset(document string) (int64, error) {
|
||||||
|
dec := json.NewDecoder(strings.NewReader(document))
|
||||||
|
var offset int64
|
||||||
|
for _, ttk := range p.DecodedTokens() {
|
||||||
|
tk, err := dec.Token()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
switch tk := tk.(type) {
|
||||||
|
case json.Delim:
|
||||||
|
switch tk {
|
||||||
|
case '{':
|
||||||
|
offset, err = offsetSingleObject(dec, ttk)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
case '[':
|
||||||
|
offset, err = offsetSingleArray(dec, ttk)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("invalid token %#v", tk)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("invalid token %#v", tk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return offset, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
|
||||||
|
for dec.More() {
|
||||||
|
offset := dec.InputOffset()
|
||||||
|
tk, err := dec.Token()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
switch tk := tk.(type) {
|
||||||
|
case json.Delim:
|
||||||
|
switch tk {
|
||||||
|
case '{':
|
||||||
|
if err = drainSingle(dec); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
case '[':
|
||||||
|
if err = drainSingle(dec); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
if tk == decodedToken {
|
||||||
|
return offset, nil
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("invalid token %#v", tk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("token reference %q not found", decodedToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) {
|
||||||
|
idx, err := strconv.Atoi(decodedToken)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("token reference %q is not a number: %v", decodedToken, err)
|
||||||
|
}
|
||||||
|
var i int
|
||||||
|
for i = 0; i < idx && dec.More(); i++ {
|
||||||
|
tk, err := dec.Token()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if delim, isDelim := tk.(json.Delim); isDelim {
|
||||||
|
switch delim {
|
||||||
|
case '{':
|
||||||
|
if err = drainSingle(dec); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
case '[':
|
||||||
|
if err = drainSingle(dec); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !dec.More() {
|
||||||
|
return 0, fmt.Errorf("token reference %q not found", decodedToken)
|
||||||
|
}
|
||||||
|
return dec.InputOffset(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// drainSingle drains a single level of object or array.
|
||||||
|
// The decoder has to guarantee the beginning delim (i.e. '{' or '[') has been consumed.
|
||||||
|
func drainSingle(dec *json.Decoder) error {
|
||||||
|
for dec.More() {
|
||||||
|
tk, err := dec.Token()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if delim, isDelim := tk.(json.Delim); isDelim {
|
||||||
|
switch delim {
|
||||||
|
case '{':
|
||||||
|
if err = drainSingle(dec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case '[':
|
||||||
|
if err = drainSingle(dec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consumes the ending delim
|
||||||
|
if _, err := dec.Token(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specific JSON pointer encoding here
|
||||||
|
// ~0 => ~
|
||||||
|
// ~1 => /
|
||||||
|
// ... and vice versa
|
||||||
|
|
||||||
|
const (
|
||||||
|
encRefTok0 = `~0`
|
||||||
|
encRefTok1 = `~1`
|
||||||
|
decRefTok0 = `~`
|
||||||
|
decRefTok1 = `/`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unescape unescapes a json pointer reference token string to the original representation
|
||||||
|
func Unescape(token string) string {
|
||||||
|
step1 := strings.ReplaceAll(token, encRefTok1, decRefTok1)
|
||||||
|
step2 := strings.ReplaceAll(step1, encRefTok0, decRefTok0)
|
||||||
|
return step2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escape escapes a pointer reference token string
|
||||||
|
func Escape(token string) string {
|
||||||
|
step1 := strings.ReplaceAll(token, decRefTok0, encRefTok0)
|
||||||
|
step2 := strings.ReplaceAll(step1, decRefTok1, encRefTok1)
|
||||||
|
return step2
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
secrets.yml
|
|
@ -0,0 +1,61 @@
|
||||||
|
linters-settings:
|
||||||
|
govet:
|
||||||
|
check-shadowing: true
|
||||||
|
golint:
|
||||||
|
min-confidence: 0
|
||||||
|
gocyclo:
|
||||||
|
min-complexity: 45
|
||||||
|
maligned:
|
||||||
|
suggest-new: true
|
||||||
|
dupl:
|
||||||
|
threshold: 200
|
||||||
|
goconst:
|
||||||
|
min-len: 2
|
||||||
|
min-occurrences: 3
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable-all: true
|
||||||
|
disable:
|
||||||
|
- maligned
|
||||||
|
- unparam
|
||||||
|
- lll
|
||||||
|
- gochecknoinits
|
||||||
|
- gochecknoglobals
|
||||||
|
- funlen
|
||||||
|
- godox
|
||||||
|
- gocognit
|
||||||
|
- whitespace
|
||||||
|
- wsl
|
||||||
|
- wrapcheck
|
||||||
|
- testpackage
|
||||||
|
- nlreturn
|
||||||
|
- gomnd
|
||||||
|
- exhaustivestruct
|
||||||
|
- goerr113
|
||||||
|
- errorlint
|
||||||
|
- nestif
|
||||||
|
- godot
|
||||||
|
- gofumpt
|
||||||
|
- paralleltest
|
||||||
|
- tparallel
|
||||||
|
- thelper
|
||||||
|
- ifshort
|
||||||
|
- exhaustruct
|
||||||
|
- varnamelen
|
||||||
|
- gci
|
||||||
|
- depguard
|
||||||
|
- errchkjson
|
||||||
|
- inamedparam
|
||||||
|
- nonamedreturns
|
||||||
|
- musttag
|
||||||
|
- ireturn
|
||||||
|
- forcetypeassert
|
||||||
|
- cyclop
|
||||||
|
# deprecated linters
|
||||||
|
- deadcode
|
||||||
|
- interfacer
|
||||||
|
- scopelint
|
||||||
|
- varcheck
|
||||||
|
- structcheck
|
||||||
|
- golint
|
||||||
|
- nosnakecase
|
|
@ -0,0 +1,74 @@
|
||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In 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.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment
|
||||||
|
include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
|
advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic
|
||||||
|
address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project 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.
|
||||||
|
|
||||||
|
Project 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.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This 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.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by contacting the project team at ivan+abuse@flanders.co.nz. All
|
||||||
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
|
is deemed necessary and 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.
|
||||||
|
|
||||||
|
Project 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.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at [http://contributor-covenant.org/version/1/4][version]
|
||||||
|
|
||||||
|
[homepage]: http://contributor-covenant.org
|
||||||
|
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -0,0 +1,19 @@
|
||||||
|
# gojsonreference [![Build Status](https://github.com/go-openapi/jsonreference/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/jsonreference/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/jsonreference/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonreference)
|
||||||
|
|
||||||
|
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
|
||||||
|
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonreference/master/LICENSE)
|
||||||
|
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/jsonreference.svg)](https://pkg.go.dev/github.com/go-openapi/jsonreference)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/jsonreference)](https://goreportcard.com/report/github.com/go-openapi/jsonreference)
|
||||||
|
|
||||||
|
An implementation of JSON Reference - Go language
|
||||||
|
|
||||||
|
## Status
|
||||||
|
Feature complete. Stable API
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
* https://github.com/go-openapi/jsonpointer
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
* http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
|
||||||
|
* http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03
|
69
vendor/github.com/go-openapi/jsonreference/internal/normalize_url.go
generated
vendored
Normal file
69
vendor/github.com/go-openapi/jsonreference/internal/normalize_url.go
generated
vendored
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultHTTPPort = ":80"
|
||||||
|
defaultHTTPSPort = ":443"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Regular expressions used by the normalizations
|
||||||
|
var rxPort = regexp.MustCompile(`(:\d+)/?$`)
|
||||||
|
var rxDupSlashes = regexp.MustCompile(`/{2,}`)
|
||||||
|
|
||||||
|
// NormalizeURL will normalize the specified URL
|
||||||
|
// This was added to replace a previous call to the no longer maintained purell library:
|
||||||
|
// The call that was used looked like the following:
|
||||||
|
//
|
||||||
|
// url.Parse(purell.NormalizeURL(parsed, purell.FlagsSafe|purell.FlagRemoveDuplicateSlashes))
|
||||||
|
//
|
||||||
|
// To explain all that was included in the call above, purell.FlagsSafe was really just the following:
|
||||||
|
// - FlagLowercaseScheme
|
||||||
|
// - FlagLowercaseHost
|
||||||
|
// - FlagRemoveDefaultPort
|
||||||
|
// - FlagRemoveDuplicateSlashes (and this was mixed in with the |)
|
||||||
|
//
|
||||||
|
// This also normalizes the URL into its urlencoded form by removing RawPath and RawFragment.
|
||||||
|
func NormalizeURL(u *url.URL) {
|
||||||
|
lowercaseScheme(u)
|
||||||
|
lowercaseHost(u)
|
||||||
|
removeDefaultPort(u)
|
||||||
|
removeDuplicateSlashes(u)
|
||||||
|
|
||||||
|
u.RawPath = ""
|
||||||
|
u.RawFragment = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func lowercaseScheme(u *url.URL) {
|
||||||
|
if len(u.Scheme) > 0 {
|
||||||
|
u.Scheme = strings.ToLower(u.Scheme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lowercaseHost(u *url.URL) {
|
||||||
|
if len(u.Host) > 0 {
|
||||||
|
u.Host = strings.ToLower(u.Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeDefaultPort(u *url.URL) {
|
||||||
|
if len(u.Host) > 0 {
|
||||||
|
scheme := strings.ToLower(u.Scheme)
|
||||||
|
u.Host = rxPort.ReplaceAllStringFunc(u.Host, func(val string) string {
|
||||||
|
if (scheme == "http" && val == defaultHTTPPort) || (scheme == "https" && val == defaultHTTPSPort) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeDuplicateSlashes(u *url.URL) {
|
||||||
|
if len(u.Path) > 0 {
|
||||||
|
u.Path = rxDupSlashes.ReplaceAllString(u.Path, "/")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// author sigu-399
|
||||||
|
// author-github https://github.com/sigu-399
|
||||||
|
// author-mail sigu.399@gmail.com
|
||||||
|
//
|
||||||
|
// repository-name jsonreference
|
||||||
|
// repository-desc An implementation of JSON Reference - Go language
|
||||||
|
//
|
||||||
|
// description Main and unique file.
|
||||||
|
//
|
||||||
|
// created 26-02-2013
|
||||||
|
|
||||||
|
package jsonreference
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-openapi/jsonpointer"
|
||||||
|
"github.com/go-openapi/jsonreference/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
fragmentRune = `#`
|
||||||
|
)
|
||||||
|
|
||||||
|
// New creates a new reference for the given string
|
||||||
|
func New(jsonReferenceString string) (Ref, error) {
|
||||||
|
|
||||||
|
var r Ref
|
||||||
|
err := r.parse(jsonReferenceString)
|
||||||
|
return r, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustCreateRef parses the ref string and panics when it's invalid.
|
||||||
|
// Use the New method for a version that returns an error
|
||||||
|
func MustCreateRef(ref string) Ref {
|
||||||
|
r, err := New(ref)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref represents a json reference object
|
||||||
|
type Ref struct {
|
||||||
|
referenceURL *url.URL
|
||||||
|
referencePointer jsonpointer.Pointer
|
||||||
|
|
||||||
|
HasFullURL bool
|
||||||
|
HasURLPathOnly bool
|
||||||
|
HasFragmentOnly bool
|
||||||
|
HasFileScheme bool
|
||||||
|
HasFullFilePath bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetURL gets the URL for this reference
|
||||||
|
func (r *Ref) GetURL() *url.URL {
|
||||||
|
return r.referenceURL
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPointer gets the json pointer for this reference
|
||||||
|
func (r *Ref) GetPointer() *jsonpointer.Pointer {
|
||||||
|
return &r.referencePointer
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the best version of the url for this reference
|
||||||
|
func (r *Ref) String() string {
|
||||||
|
|
||||||
|
if r.referenceURL != nil {
|
||||||
|
return r.referenceURL.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.HasFragmentOnly {
|
||||||
|
return fragmentRune + r.referencePointer.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.referencePointer.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRoot returns true if this reference is a root document
|
||||||
|
func (r *Ref) IsRoot() bool {
|
||||||
|
return r.referenceURL != nil &&
|
||||||
|
!r.IsCanonical() &&
|
||||||
|
!r.HasURLPathOnly &&
|
||||||
|
r.referenceURL.Fragment == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCanonical returns true when this pointer starts with http(s):// or file://
|
||||||
|
func (r *Ref) IsCanonical() bool {
|
||||||
|
return (r.HasFileScheme && r.HasFullFilePath) || (!r.HasFileScheme && r.HasFullURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Constructor", parses the given string JSON reference
|
||||||
|
func (r *Ref) parse(jsonReferenceString string) error {
|
||||||
|
|
||||||
|
parsed, err := url.Parse(jsonReferenceString)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
internal.NormalizeURL(parsed)
|
||||||
|
|
||||||
|
r.referenceURL = parsed
|
||||||
|
refURL := r.referenceURL
|
||||||
|
|
||||||
|
if refURL.Scheme != "" && refURL.Host != "" {
|
||||||
|
r.HasFullURL = true
|
||||||
|
} else {
|
||||||
|
if refURL.Path != "" {
|
||||||
|
r.HasURLPathOnly = true
|
||||||
|
} else if refURL.RawQuery == "" && refURL.Fragment != "" {
|
||||||
|
r.HasFragmentOnly = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.HasFileScheme = refURL.Scheme == "file"
|
||||||
|
r.HasFullFilePath = strings.HasPrefix(refURL.Path, "/")
|
||||||
|
|
||||||
|
// invalid json-pointer error means url has no json-pointer fragment. simply ignore error
|
||||||
|
r.referencePointer, _ = jsonpointer.New(refURL.Fragment)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherits creates a new reference from a parent and a child
|
||||||
|
// If the child cannot inherit from the parent, an error is returned
|
||||||
|
func (r *Ref) Inherits(child Ref) (*Ref, error) {
|
||||||
|
childURL := child.GetURL()
|
||||||
|
parentURL := r.GetURL()
|
||||||
|
if childURL == nil {
|
||||||
|
return nil, errors.New("child url is nil")
|
||||||
|
}
|
||||||
|
if parentURL == nil {
|
||||||
|
return &child, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ref, err := New(parentURL.ResolveReference(childURL).String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ref, nil
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Unix-style newlines with a newline ending every file
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# Set default charset
|
||||||
|
[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
|
||||||
|
charset = utf-8
|
||||||
|
|
||||||
|
# Tab indentation (no size specified)
|
||||||
|
[*.go]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
# Matches the exact files either package.json or .travis.yml
|
||||||
|
[{package.json,.travis.yml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
|
@ -0,0 +1 @@
|
||||||
|
*.out
|
|
@ -0,0 +1,61 @@
|
||||||
|
linters-settings:
|
||||||
|
govet:
|
||||||
|
check-shadowing: true
|
||||||
|
golint:
|
||||||
|
min-confidence: 0
|
||||||
|
gocyclo:
|
||||||
|
min-complexity: 45
|
||||||
|
maligned:
|
||||||
|
suggest-new: true
|
||||||
|
dupl:
|
||||||
|
threshold: 200
|
||||||
|
goconst:
|
||||||
|
min-len: 2
|
||||||
|
min-occurrences: 3
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable-all: true
|
||||||
|
disable:
|
||||||
|
- maligned
|
||||||
|
- unparam
|
||||||
|
- lll
|
||||||
|
- gochecknoinits
|
||||||
|
- gochecknoglobals
|
||||||
|
- funlen
|
||||||
|
- godox
|
||||||
|
- gocognit
|
||||||
|
- whitespace
|
||||||
|
- wsl
|
||||||
|
- wrapcheck
|
||||||
|
- testpackage
|
||||||
|
- nlreturn
|
||||||
|
- gomnd
|
||||||
|
- exhaustivestruct
|
||||||
|
- goerr113
|
||||||
|
- errorlint
|
||||||
|
- nestif
|
||||||
|
- godot
|
||||||
|
- gofumpt
|
||||||
|
- paralleltest
|
||||||
|
- tparallel
|
||||||
|
- thelper
|
||||||
|
- ifshort
|
||||||
|
- exhaustruct
|
||||||
|
- varnamelen
|
||||||
|
- gci
|
||||||
|
- depguard
|
||||||
|
- errchkjson
|
||||||
|
- inamedparam
|
||||||
|
- nonamedreturns
|
||||||
|
- musttag
|
||||||
|
- ireturn
|
||||||
|
- forcetypeassert
|
||||||
|
- cyclop
|
||||||
|
# deprecated linters
|
||||||
|
- deadcode
|
||||||
|
- interfacer
|
||||||
|
- scopelint
|
||||||
|
- varcheck
|
||||||
|
- structcheck
|
||||||
|
- golint
|
||||||
|
- nosnakecase
|
|
@ -0,0 +1,74 @@
|
||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In 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.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment
|
||||||
|
include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
|
advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic
|
||||||
|
address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project 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.
|
||||||
|
|
||||||
|
Project 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.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This 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.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by contacting the project team at ivan+abuse@flanders.co.nz. All
|
||||||
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
|
is deemed necessary and 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.
|
||||||
|
|
||||||
|
Project 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.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at [http://contributor-covenant.org/version/1/4][version]
|
||||||
|
|
||||||
|
[homepage]: http://contributor-covenant.org
|
||||||
|
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -0,0 +1,54 @@
|
||||||
|
# OpenAPI v2 object model [![Build Status](https://github.com/go-openapi/spec/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/spec/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/spec/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/spec)
|
||||||
|
|
||||||
|
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
|
||||||
|
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/spec/master/LICENSE)
|
||||||
|
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/spec.svg)](https://pkg.go.dev/github.com/go-openapi/spec)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/spec)](https://goreportcard.com/report/github.com/go-openapi/spec)
|
||||||
|
|
||||||
|
The object model for OpenAPI specification documents.
|
||||||
|
|
||||||
|
### FAQ
|
||||||
|
|
||||||
|
* What does this do?
|
||||||
|
|
||||||
|
> 1. This package knows how to marshal and unmarshal Swagger API specifications into a golang object model
|
||||||
|
> 2. It knows how to resolve $ref and expand them to make a single root document
|
||||||
|
|
||||||
|
* How does it play with the rest of the go-openapi packages ?
|
||||||
|
|
||||||
|
> 1. This package is at the core of the go-openapi suite of packages and [code generator](https://github.com/go-swagger/go-swagger)
|
||||||
|
> 2. There is a [spec loading package](https://github.com/go-openapi/loads) to fetch specs as JSON or YAML from local or remote locations
|
||||||
|
> 3. There is a [spec validation package](https://github.com/go-openapi/validate) built on top of it
|
||||||
|
> 4. There is a [spec analysis package](https://github.com/go-openapi/analysis) built on top of it, to analyze, flatten, fix and merge spec documents
|
||||||
|
|
||||||
|
* Does this library support OpenAPI 3?
|
||||||
|
|
||||||
|
> No.
|
||||||
|
> This package currently only supports OpenAPI 2.0 (aka Swagger 2.0).
|
||||||
|
> There is no plan to make it evolve toward supporting OpenAPI 3.x.
|
||||||
|
> This [discussion thread](https://github.com/go-openapi/spec/issues/21) relates the full story.
|
||||||
|
>
|
||||||
|
> An early attempt to support Swagger 3 may be found at: https://github.com/go-openapi/spec3
|
||||||
|
|
||||||
|
* Does the unmarshaling support YAML?
|
||||||
|
|
||||||
|
> Not directly. The exposed types know only how to unmarshal from JSON.
|
||||||
|
>
|
||||||
|
> In order to load a YAML document as a Swagger spec, you need to use the loaders provided by
|
||||||
|
> github.com/go-openapi/loads
|
||||||
|
>
|
||||||
|
> Take a look at the example there: https://pkg.go.dev/github.com/go-openapi/loads#example-Spec
|
||||||
|
>
|
||||||
|
> See also https://github.com/go-openapi/spec/issues/164
|
||||||
|
|
||||||
|
* How can I validate a spec?
|
||||||
|
|
||||||
|
> Validation is provided by [the validate package](http://github.com/go-openapi/validate)
|
||||||
|
|
||||||
|
* Why do we have an `ID` field for `Schema` which is not part of the swagger spec?
|
||||||
|
|
||||||
|
> We found jsonschema compatibility more important: since `id` in jsonschema influences
|
||||||
|
> how `$ref` are resolved.
|
||||||
|
> This `id` does not conflict with any property named `id`.
|
||||||
|
>
|
||||||
|
> See also https://github.com/go-openapi/spec/issues/23
|
|
@ -0,0 +1,98 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResolutionCache a cache for resolving urls
|
||||||
|
type ResolutionCache interface {
|
||||||
|
Get(string) (interface{}, bool)
|
||||||
|
Set(string, interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type simpleCache struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
store map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *simpleCache) ShallowClone() ResolutionCache {
|
||||||
|
store := make(map[string]interface{}, len(s.store))
|
||||||
|
s.lock.RLock()
|
||||||
|
for k, v := range s.store {
|
||||||
|
store[k] = v
|
||||||
|
}
|
||||||
|
s.lock.RUnlock()
|
||||||
|
|
||||||
|
return &simpleCache{
|
||||||
|
store: store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a cached URI
|
||||||
|
func (s *simpleCache) Get(uri string) (interface{}, bool) {
|
||||||
|
s.lock.RLock()
|
||||||
|
v, ok := s.store[uri]
|
||||||
|
|
||||||
|
s.lock.RUnlock()
|
||||||
|
return v, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set caches a URI
|
||||||
|
func (s *simpleCache) Set(uri string, data interface{}) {
|
||||||
|
s.lock.Lock()
|
||||||
|
s.store[uri] = data
|
||||||
|
s.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// resCache is a package level cache for $ref resolution and expansion.
|
||||||
|
// It is initialized lazily by methods that have the need for it: no
|
||||||
|
// memory is allocated unless some expander methods are called.
|
||||||
|
//
|
||||||
|
// It is initialized with JSON schema and swagger schema,
|
||||||
|
// which do not mutate during normal operations.
|
||||||
|
//
|
||||||
|
// All subsequent utilizations of this cache are produced from a shallow
|
||||||
|
// clone of this initial version.
|
||||||
|
resCache *simpleCache
|
||||||
|
onceCache sync.Once
|
||||||
|
|
||||||
|
_ ResolutionCache = &simpleCache{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// initResolutionCache initializes the URI resolution cache. To be wrapped in a sync.Once.Do call.
|
||||||
|
func initResolutionCache() {
|
||||||
|
resCache = defaultResolutionCache()
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultResolutionCache() *simpleCache {
|
||||||
|
return &simpleCache{store: map[string]interface{}{
|
||||||
|
"http://swagger.io/v2/schema.json": MustLoadSwagger20Schema(),
|
||||||
|
"http://json-schema.org/draft-04/schema": MustLoadJSONSchemaDraft04(),
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cacheOrDefault(cache ResolutionCache) ResolutionCache {
|
||||||
|
onceCache.Do(initResolutionCache)
|
||||||
|
|
||||||
|
if cache != nil {
|
||||||
|
return cache
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a shallow clone of the base cache with swagger and json schema
|
||||||
|
return resCache.ShallowClone()
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContactInfo contact information for the exposed API.
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#contactObject
|
||||||
|
type ContactInfo struct {
|
||||||
|
ContactInfoProps
|
||||||
|
VendorExtensible
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContactInfoProps hold the properties of a ContactInfo object
|
||||||
|
type ContactInfoProps struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
Email string `json:"email,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON hydrates ContactInfo from json
|
||||||
|
func (c *ContactInfo) UnmarshalJSON(data []byte) error {
|
||||||
|
if err := json.Unmarshal(data, &c.ContactInfoProps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, &c.VendorExtensible)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON produces ContactInfo as json
|
||||||
|
func (c ContactInfo) MarshalJSON() ([]byte, error) {
|
||||||
|
b1, err := json.Marshal(c.ContactInfoProps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b2, err := json.Marshal(c.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return swag.ConcatJSON(b1, b2), nil
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Debug is true when the SWAGGER_DEBUG env var is not empty.
|
||||||
|
//
|
||||||
|
// It enables a more verbose logging of this package.
|
||||||
|
var Debug = os.Getenv("SWAGGER_DEBUG") != ""
|
||||||
|
|
||||||
|
var (
|
||||||
|
// specLogger is a debug logger for this package
|
||||||
|
specLogger *log.Logger
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
debugOptions()
|
||||||
|
}
|
||||||
|
|
||||||
|
func debugOptions() {
|
||||||
|
specLogger = log.New(os.Stdout, "spec:", log.LstdFlags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func debugLog(msg string, args ...interface{}) {
|
||||||
|
// A private, trivial trace logger, based on go-openapi/spec/expander.go:debugLog()
|
||||||
|
if Debug {
|
||||||
|
_, file1, pos1, _ := runtime.Caller(1)
|
||||||
|
specLogger.Printf("%s:%d: %s", path.Base(file1), pos1, fmt.Sprintf(msg, args...))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed schemas/*.json schemas/*/*.json
|
||||||
|
var assets embed.FS
|
||||||
|
|
||||||
|
func jsonschemaDraft04JSONBytes() ([]byte, error) {
|
||||||
|
return assets.ReadFile(path.Join("schemas", "jsonschema-draft-04.json"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func v2SchemaJSONBytes() ([]byte, error) {
|
||||||
|
return assets.ReadFile(path.Join("schemas", "v2", "schema.json"))
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
// Error codes
|
||||||
|
var (
|
||||||
|
// ErrUnknownTypeForReference indicates that a resolved reference was found in an unsupported container type
|
||||||
|
ErrUnknownTypeForReference = errors.New("unknown type for the resolved reference")
|
||||||
|
|
||||||
|
// ErrResolveRefNeedsAPointer indicates that a $ref target must be a valid JSON pointer
|
||||||
|
ErrResolveRefNeedsAPointer = errors.New("resolve ref: target needs to be a pointer")
|
||||||
|
|
||||||
|
// ErrDerefUnsupportedType indicates that a resolved reference was found in an unsupported container type.
|
||||||
|
// At the moment, $ref are supported only inside: schemas, parameters, responses, path items
|
||||||
|
ErrDerefUnsupportedType = errors.New("deref: unsupported type")
|
||||||
|
|
||||||
|
// ErrExpandUnsupportedType indicates that $ref expansion is attempted on some invalid type
|
||||||
|
ErrExpandUnsupportedType = errors.New("expand: unsupported type. Input should be of type *Parameter or *Response")
|
||||||
|
)
|
|
@ -0,0 +1,607 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExpandOptions provides options for the spec expander.
|
||||||
|
//
|
||||||
|
// RelativeBase is the path to the root document. This can be a remote URL or a path to a local file.
|
||||||
|
//
|
||||||
|
// If left empty, the root document is assumed to be located in the current working directory:
|
||||||
|
// all relative $ref's will be resolved from there.
|
||||||
|
//
|
||||||
|
// PathLoader injects a document loading method. By default, this resolves to the function provided by the SpecLoader package variable.
|
||||||
|
type ExpandOptions struct {
|
||||||
|
RelativeBase string // the path to the root document to expand. This is a file, not a directory
|
||||||
|
SkipSchemas bool // do not expand schemas, just paths, parameters and responses
|
||||||
|
ContinueOnError bool // continue expanding even after and error is found
|
||||||
|
PathLoader func(string) (json.RawMessage, error) `json:"-"` // the document loading method that takes a path as input and yields a json document
|
||||||
|
AbsoluteCircularRef bool // circular $ref remaining after expansion remain absolute URLs
|
||||||
|
}
|
||||||
|
|
||||||
|
func optionsOrDefault(opts *ExpandOptions) *ExpandOptions {
|
||||||
|
if opts != nil {
|
||||||
|
clone := *opts // shallow clone to avoid internal changes to be propagated to the caller
|
||||||
|
if clone.RelativeBase != "" {
|
||||||
|
clone.RelativeBase = normalizeBase(clone.RelativeBase)
|
||||||
|
}
|
||||||
|
// if the relative base is empty, let the schema loader choose a pseudo root document
|
||||||
|
return &clone
|
||||||
|
}
|
||||||
|
return &ExpandOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandSpec expands the references in a swagger spec
|
||||||
|
func ExpandSpec(spec *Swagger, options *ExpandOptions) error {
|
||||||
|
options = optionsOrDefault(options)
|
||||||
|
resolver := defaultSchemaLoader(spec, options, nil, nil)
|
||||||
|
|
||||||
|
specBasePath := options.RelativeBase
|
||||||
|
|
||||||
|
if !options.SkipSchemas {
|
||||||
|
for key, definition := range spec.Definitions {
|
||||||
|
parentRefs := make([]string, 0, 10)
|
||||||
|
parentRefs = append(parentRefs, "#/definitions/"+key)
|
||||||
|
|
||||||
|
def, err := expandSchema(definition, parentRefs, resolver, specBasePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if def != nil {
|
||||||
|
spec.Definitions[key] = *def
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for key := range spec.Parameters {
|
||||||
|
parameter := spec.Parameters[key]
|
||||||
|
if err := expandParameterOrResponse(¶meter, resolver, specBasePath); resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
spec.Parameters[key] = parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
for key := range spec.Responses {
|
||||||
|
response := spec.Responses[key]
|
||||||
|
if err := expandParameterOrResponse(&response, resolver, specBasePath); resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
spec.Responses[key] = response
|
||||||
|
}
|
||||||
|
|
||||||
|
if spec.Paths != nil {
|
||||||
|
for key := range spec.Paths.Paths {
|
||||||
|
pth := spec.Paths.Paths[key]
|
||||||
|
if err := expandPathItem(&pth, resolver, specBasePath); resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
spec.Paths.Paths[key] = pth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootBase = ".root"
|
||||||
|
|
||||||
|
// baseForRoot loads in the cache the root document and produces a fake ".root" base path entry
|
||||||
|
// for further $ref resolution
|
||||||
|
func baseForRoot(root interface{}, cache ResolutionCache) string {
|
||||||
|
// cache the root document to resolve $ref's
|
||||||
|
normalizedBase := normalizeBase(rootBase)
|
||||||
|
|
||||||
|
if root == nil {
|
||||||
|
// ensure that we never leave a nil root: always cache the root base pseudo-document
|
||||||
|
cachedRoot, found := cache.Get(normalizedBase)
|
||||||
|
if found && cachedRoot != nil {
|
||||||
|
// the cache is already preloaded with a root
|
||||||
|
return normalizedBase
|
||||||
|
}
|
||||||
|
|
||||||
|
root = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.Set(normalizedBase, root)
|
||||||
|
|
||||||
|
return normalizedBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandSchema expands the refs in the schema object with reference to the root object.
|
||||||
|
//
|
||||||
|
// go-openapi/validate uses this function.
|
||||||
|
//
|
||||||
|
// Notice that it is impossible to reference a json schema in a different document other than root
|
||||||
|
// (use ExpandSchemaWithBasePath to resolve external references).
|
||||||
|
//
|
||||||
|
// Setting the cache is optional and this parameter may safely be left to nil.
|
||||||
|
func ExpandSchema(schema *Schema, root interface{}, cache ResolutionCache) error {
|
||||||
|
cache = cacheOrDefault(cache)
|
||||||
|
if root == nil {
|
||||||
|
root = schema
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := &ExpandOptions{
|
||||||
|
// when a root is specified, cache the root as an in-memory document for $ref retrieval
|
||||||
|
RelativeBase: baseForRoot(root, cache),
|
||||||
|
SkipSchemas: false,
|
||||||
|
ContinueOnError: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExpandSchemaWithBasePath(schema, cache, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandSchemaWithBasePath expands the refs in the schema object, base path configured through expand options.
|
||||||
|
//
|
||||||
|
// Setting the cache is optional and this parameter may safely be left to nil.
|
||||||
|
func ExpandSchemaWithBasePath(schema *Schema, cache ResolutionCache, opts *ExpandOptions) error {
|
||||||
|
if schema == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cache = cacheOrDefault(cache)
|
||||||
|
|
||||||
|
opts = optionsOrDefault(opts)
|
||||||
|
|
||||||
|
resolver := defaultSchemaLoader(nil, opts, cache, nil)
|
||||||
|
|
||||||
|
parentRefs := make([]string, 0, 10)
|
||||||
|
s, err := expandSchema(*schema, parentRefs, resolver, opts.RelativeBase)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if s != nil {
|
||||||
|
// guard for when continuing on error
|
||||||
|
*schema = *s
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandItems(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) {
|
||||||
|
if target.Items == nil {
|
||||||
|
return &target, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// array
|
||||||
|
if target.Items.Schema != nil {
|
||||||
|
t, err := expandSchema(*target.Items.Schema, parentRefs, resolver, basePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
*target.Items.Schema = *t
|
||||||
|
}
|
||||||
|
|
||||||
|
// tuple
|
||||||
|
for i := range target.Items.Schemas {
|
||||||
|
t, err := expandSchema(target.Items.Schemas[i], parentRefs, resolver, basePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
target.Items.Schemas[i] = *t
|
||||||
|
}
|
||||||
|
|
||||||
|
return &target, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) {
|
||||||
|
if target.Ref.String() == "" && target.Ref.IsRoot() {
|
||||||
|
newRef := normalizeRef(&target.Ref, basePath)
|
||||||
|
target.Ref = *newRef
|
||||||
|
return &target, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// change the base path of resolution when an ID is encountered
|
||||||
|
// otherwise the basePath should inherit the parent's
|
||||||
|
if target.ID != "" {
|
||||||
|
basePath, _ = resolver.setSchemaID(target, target.ID, basePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.Ref.String() != "" {
|
||||||
|
if !resolver.options.SkipSchemas {
|
||||||
|
return expandSchemaRef(target, parentRefs, resolver, basePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// when "expand" with SkipSchema, we just rebase the existing $ref without replacing
|
||||||
|
// the full schema.
|
||||||
|
rebasedRef, err := NewRef(normalizeURI(target.Ref.String(), basePath))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
target.Ref = denormalizeRef(&rebasedRef, resolver.context.basePath, resolver.context.rootID)
|
||||||
|
|
||||||
|
return &target, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range target.Definitions {
|
||||||
|
tt, err := expandSchema(target.Definitions[k], parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return &target, err
|
||||||
|
}
|
||||||
|
if tt != nil {
|
||||||
|
target.Definitions[k] = *tt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := expandItems(target, parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return &target, err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
target = *t
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range target.AllOf {
|
||||||
|
t, err := expandSchema(target.AllOf[i], parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return &target, err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
target.AllOf[i] = *t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range target.AnyOf {
|
||||||
|
t, err := expandSchema(target.AnyOf[i], parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return &target, err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
target.AnyOf[i] = *t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range target.OneOf {
|
||||||
|
t, err := expandSchema(target.OneOf[i], parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return &target, err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
target.OneOf[i] = *t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.Not != nil {
|
||||||
|
t, err := expandSchema(*target.Not, parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return &target, err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
*target.Not = *t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range target.Properties {
|
||||||
|
t, err := expandSchema(target.Properties[k], parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return &target, err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
target.Properties[k] = *t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.AdditionalProperties != nil && target.AdditionalProperties.Schema != nil {
|
||||||
|
t, err := expandSchema(*target.AdditionalProperties.Schema, parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return &target, err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
*target.AdditionalProperties.Schema = *t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range target.PatternProperties {
|
||||||
|
t, err := expandSchema(target.PatternProperties[k], parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return &target, err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
target.PatternProperties[k] = *t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range target.Dependencies {
|
||||||
|
if target.Dependencies[k].Schema != nil {
|
||||||
|
t, err := expandSchema(*target.Dependencies[k].Schema, parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return &target, err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
*target.Dependencies[k].Schema = *t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.AdditionalItems != nil && target.AdditionalItems.Schema != nil {
|
||||||
|
t, err := expandSchema(*target.AdditionalItems.Schema, parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return &target, err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
*target.AdditionalItems.Schema = *t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &target, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandSchemaRef(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) {
|
||||||
|
// if a Ref is found, all sibling fields are skipped
|
||||||
|
// Ref also changes the resolution scope of children expandSchema
|
||||||
|
|
||||||
|
// here the resolution scope is changed because a $ref was encountered
|
||||||
|
normalizedRef := normalizeRef(&target.Ref, basePath)
|
||||||
|
normalizedBasePath := normalizedRef.RemoteURI()
|
||||||
|
|
||||||
|
if resolver.isCircular(normalizedRef, basePath, parentRefs...) {
|
||||||
|
// this means there is a cycle in the recursion tree: return the Ref
|
||||||
|
// - circular refs cannot be expanded. We leave them as ref.
|
||||||
|
// - denormalization means that a new local file ref is set relative to the original basePath
|
||||||
|
debugLog("short circuit circular ref: basePath: %s, normalizedPath: %s, normalized ref: %s",
|
||||||
|
basePath, normalizedBasePath, normalizedRef.String())
|
||||||
|
if !resolver.options.AbsoluteCircularRef {
|
||||||
|
target.Ref = denormalizeRef(normalizedRef, resolver.context.basePath, resolver.context.rootID)
|
||||||
|
} else {
|
||||||
|
target.Ref = *normalizedRef
|
||||||
|
}
|
||||||
|
return &target, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var t *Schema
|
||||||
|
err := resolver.Resolve(&target.Ref, &t, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if t == nil {
|
||||||
|
// guard for when continuing on error
|
||||||
|
return &target, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
parentRefs = append(parentRefs, normalizedRef.String())
|
||||||
|
transitiveResolver := resolver.transitiveResolver(basePath, target.Ref)
|
||||||
|
|
||||||
|
basePath = resolver.updateBasePath(transitiveResolver, normalizedBasePath)
|
||||||
|
|
||||||
|
return expandSchema(*t, parentRefs, transitiveResolver, basePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandPathItem(pathItem *PathItem, resolver *schemaLoader, basePath string) error {
|
||||||
|
if pathItem == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
parentRefs := make([]string, 0, 10)
|
||||||
|
if err := resolver.deref(pathItem, parentRefs, basePath); resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if pathItem.Ref.String() != "" {
|
||||||
|
transitiveResolver := resolver.transitiveResolver(basePath, pathItem.Ref)
|
||||||
|
basePath = transitiveResolver.updateBasePath(resolver, basePath)
|
||||||
|
resolver = transitiveResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
pathItem.Ref = Ref{}
|
||||||
|
for i := range pathItem.Parameters {
|
||||||
|
if err := expandParameterOrResponse(&(pathItem.Parameters[i]), resolver, basePath); resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ops := []*Operation{
|
||||||
|
pathItem.Get,
|
||||||
|
pathItem.Head,
|
||||||
|
pathItem.Options,
|
||||||
|
pathItem.Put,
|
||||||
|
pathItem.Post,
|
||||||
|
pathItem.Patch,
|
||||||
|
pathItem.Delete,
|
||||||
|
}
|
||||||
|
for _, op := range ops {
|
||||||
|
if err := expandOperation(op, resolver, basePath); resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandOperation(op *Operation, resolver *schemaLoader, basePath string) error {
|
||||||
|
if op == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range op.Parameters {
|
||||||
|
param := op.Parameters[i]
|
||||||
|
if err := expandParameterOrResponse(¶m, resolver, basePath); resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
op.Parameters[i] = param
|
||||||
|
}
|
||||||
|
|
||||||
|
if op.Responses == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
responses := op.Responses
|
||||||
|
if err := expandParameterOrResponse(responses.Default, resolver, basePath); resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for code := range responses.StatusCodeResponses {
|
||||||
|
response := responses.StatusCodeResponses[code]
|
||||||
|
if err := expandParameterOrResponse(&response, resolver, basePath); resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
responses.StatusCodeResponses[code] = response
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandResponseWithRoot expands a response based on a root document, not a fetchable document
|
||||||
|
//
|
||||||
|
// Notice that it is impossible to reference a json schema in a different document other than root
|
||||||
|
// (use ExpandResponse to resolve external references).
|
||||||
|
//
|
||||||
|
// Setting the cache is optional and this parameter may safely be left to nil.
|
||||||
|
func ExpandResponseWithRoot(response *Response, root interface{}, cache ResolutionCache) error {
|
||||||
|
cache = cacheOrDefault(cache)
|
||||||
|
opts := &ExpandOptions{
|
||||||
|
RelativeBase: baseForRoot(root, cache),
|
||||||
|
}
|
||||||
|
resolver := defaultSchemaLoader(root, opts, cache, nil)
|
||||||
|
|
||||||
|
return expandParameterOrResponse(response, resolver, opts.RelativeBase)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandResponse expands a response based on a basepath
|
||||||
|
//
|
||||||
|
// All refs inside response will be resolved relative to basePath
|
||||||
|
func ExpandResponse(response *Response, basePath string) error {
|
||||||
|
opts := optionsOrDefault(&ExpandOptions{
|
||||||
|
RelativeBase: basePath,
|
||||||
|
})
|
||||||
|
resolver := defaultSchemaLoader(nil, opts, nil, nil)
|
||||||
|
|
||||||
|
return expandParameterOrResponse(response, resolver, opts.RelativeBase)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandParameterWithRoot expands a parameter based on a root document, not a fetchable document.
|
||||||
|
//
|
||||||
|
// Notice that it is impossible to reference a json schema in a different document other than root
|
||||||
|
// (use ExpandParameter to resolve external references).
|
||||||
|
func ExpandParameterWithRoot(parameter *Parameter, root interface{}, cache ResolutionCache) error {
|
||||||
|
cache = cacheOrDefault(cache)
|
||||||
|
|
||||||
|
opts := &ExpandOptions{
|
||||||
|
RelativeBase: baseForRoot(root, cache),
|
||||||
|
}
|
||||||
|
resolver := defaultSchemaLoader(root, opts, cache, nil)
|
||||||
|
|
||||||
|
return expandParameterOrResponse(parameter, resolver, opts.RelativeBase)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandParameter expands a parameter based on a basepath.
|
||||||
|
// This is the exported version of expandParameter
|
||||||
|
// all refs inside parameter will be resolved relative to basePath
|
||||||
|
func ExpandParameter(parameter *Parameter, basePath string) error {
|
||||||
|
opts := optionsOrDefault(&ExpandOptions{
|
||||||
|
RelativeBase: basePath,
|
||||||
|
})
|
||||||
|
resolver := defaultSchemaLoader(nil, opts, nil, nil)
|
||||||
|
|
||||||
|
return expandParameterOrResponse(parameter, resolver, opts.RelativeBase)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRefAndSchema(input interface{}) (*Ref, *Schema, error) {
|
||||||
|
var (
|
||||||
|
ref *Ref
|
||||||
|
sch *Schema
|
||||||
|
)
|
||||||
|
|
||||||
|
switch refable := input.(type) {
|
||||||
|
case *Parameter:
|
||||||
|
if refable == nil {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
ref = &refable.Ref
|
||||||
|
sch = refable.Schema
|
||||||
|
case *Response:
|
||||||
|
if refable == nil {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
ref = &refable.Ref
|
||||||
|
sch = refable.Schema
|
||||||
|
default:
|
||||||
|
return nil, nil, fmt.Errorf("unsupported type: %T: %w", input, ErrExpandUnsupportedType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref, sch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandParameterOrResponse(input interface{}, resolver *schemaLoader, basePath string) error {
|
||||||
|
ref, sch, err := getRefAndSchema(input)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ref == nil && sch == nil { // nothing to do
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
parentRefs := make([]string, 0, 10)
|
||||||
|
if ref != nil {
|
||||||
|
// dereference this $ref
|
||||||
|
if err = resolver.deref(input, parentRefs, basePath); resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ref, sch, _ = getRefAndSchema(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ref.String() != "" {
|
||||||
|
transitiveResolver := resolver.transitiveResolver(basePath, *ref)
|
||||||
|
basePath = resolver.updateBasePath(transitiveResolver, basePath)
|
||||||
|
resolver = transitiveResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
if sch == nil {
|
||||||
|
// nothing to be expanded
|
||||||
|
if ref != nil {
|
||||||
|
*ref = Ref{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if sch.Ref.String() != "" {
|
||||||
|
rebasedRef, ern := NewRef(normalizeURI(sch.Ref.String(), basePath))
|
||||||
|
if ern != nil {
|
||||||
|
return ern
|
||||||
|
}
|
||||||
|
|
||||||
|
if resolver.isCircular(&rebasedRef, basePath, parentRefs...) {
|
||||||
|
// this is a circular $ref: stop expansion
|
||||||
|
if !resolver.options.AbsoluteCircularRef {
|
||||||
|
sch.Ref = denormalizeRef(&rebasedRef, resolver.context.basePath, resolver.context.rootID)
|
||||||
|
} else {
|
||||||
|
sch.Ref = rebasedRef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $ref expansion or rebasing is performed by expandSchema below
|
||||||
|
if ref != nil {
|
||||||
|
*ref = Ref{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// expand schema
|
||||||
|
// yes, we do it even if options.SkipSchema is true: we have to go down that rabbit hole and rebase nested $ref)
|
||||||
|
s, err := expandSchema(*sch, parentRefs, resolver, basePath)
|
||||||
|
if resolver.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s != nil { // guard for when continuing on error
|
||||||
|
*sch = *s
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
// ExternalDocumentation allows referencing an external resource for
|
||||||
|
// extended documentation.
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#externalDocumentationObject
|
||||||
|
type ExternalDocumentation struct {
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-openapi/jsonpointer"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
jsonArray = "array"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HeaderProps describes a response header
|
||||||
|
type HeaderProps struct {
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header describes a header for a response of the API
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#headerObject
|
||||||
|
type Header struct {
|
||||||
|
CommonValidations
|
||||||
|
SimpleSchema
|
||||||
|
VendorExtensible
|
||||||
|
HeaderProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponseHeader creates a new header instance for use in a response
|
||||||
|
func ResponseHeader() *Header {
|
||||||
|
return new(Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDescription sets the description on this response, allows for chaining
|
||||||
|
func (h *Header) WithDescription(description string) *Header {
|
||||||
|
h.Description = description
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typed a fluent builder method for the type of parameter
|
||||||
|
func (h *Header) Typed(tpe, format string) *Header {
|
||||||
|
h.Type = tpe
|
||||||
|
h.Format = format
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// CollectionOf a fluent builder method for an array item
|
||||||
|
func (h *Header) CollectionOf(items *Items, format string) *Header {
|
||||||
|
h.Type = jsonArray
|
||||||
|
h.Items = items
|
||||||
|
h.CollectionFormat = format
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDefault sets the default value on this item
|
||||||
|
func (h *Header) WithDefault(defaultValue interface{}) *Header {
|
||||||
|
h.Default = defaultValue
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxLength sets a max length value
|
||||||
|
func (h *Header) WithMaxLength(max int64) *Header {
|
||||||
|
h.MaxLength = &max
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinLength sets a min length value
|
||||||
|
func (h *Header) WithMinLength(min int64) *Header {
|
||||||
|
h.MinLength = &min
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPattern sets a pattern value
|
||||||
|
func (h *Header) WithPattern(pattern string) *Header {
|
||||||
|
h.Pattern = pattern
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMultipleOf sets a multiple of value
|
||||||
|
func (h *Header) WithMultipleOf(number float64) *Header {
|
||||||
|
h.MultipleOf = &number
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaximum sets a maximum number value
|
||||||
|
func (h *Header) WithMaximum(max float64, exclusive bool) *Header {
|
||||||
|
h.Maximum = &max
|
||||||
|
h.ExclusiveMaximum = exclusive
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinimum sets a minimum number value
|
||||||
|
func (h *Header) WithMinimum(min float64, exclusive bool) *Header {
|
||||||
|
h.Minimum = &min
|
||||||
|
h.ExclusiveMinimum = exclusive
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEnum sets a the enum values (replace)
|
||||||
|
func (h *Header) WithEnum(values ...interface{}) *Header {
|
||||||
|
h.Enum = append([]interface{}{}, values...)
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxItems sets the max items
|
||||||
|
func (h *Header) WithMaxItems(size int64) *Header {
|
||||||
|
h.MaxItems = &size
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinItems sets the min items
|
||||||
|
func (h *Header) WithMinItems(size int64) *Header {
|
||||||
|
h.MinItems = &size
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// UniqueValues dictates that this array can only have unique items
|
||||||
|
func (h *Header) UniqueValues() *Header {
|
||||||
|
h.UniqueItems = true
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowDuplicates this array can have duplicates
|
||||||
|
func (h *Header) AllowDuplicates() *Header {
|
||||||
|
h.UniqueItems = false
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithValidations is a fluent method to set header validations
|
||||||
|
func (h *Header) WithValidations(val CommonValidations) *Header {
|
||||||
|
h.SetValidations(SchemaValidations{CommonValidations: val})
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshal this to JSON
|
||||||
|
func (h Header) MarshalJSON() ([]byte, error) {
|
||||||
|
b1, err := json.Marshal(h.CommonValidations)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b2, err := json.Marshal(h.SimpleSchema)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b3, err := json.Marshal(h.HeaderProps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return swag.ConcatJSON(b1, b2, b3), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals this header from JSON
|
||||||
|
func (h *Header) UnmarshalJSON(data []byte) error {
|
||||||
|
if err := json.Unmarshal(data, &h.CommonValidations); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &h.SimpleSchema); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &h.VendorExtensible); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, &h.HeaderProps)
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONLookup look up a value by the json property name
|
||||||
|
func (h Header) JSONLookup(token string) (interface{}, error) {
|
||||||
|
if ex, ok := h.Extensions[token]; ok {
|
||||||
|
return &ex, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r, _, err := jsonpointer.GetForToken(h.CommonValidations, token)
|
||||||
|
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r != nil {
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
r, _, err = jsonpointer.GetForToken(h.SimpleSchema, token)
|
||||||
|
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r != nil {
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
r, _, err = jsonpointer.GetForToken(h.HeaderProps, token)
|
||||||
|
return r, err
|
||||||
|
}
|
|
@ -0,0 +1,184 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-openapi/jsonpointer"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Extensions vendor specific extensions
|
||||||
|
type Extensions map[string]interface{}
|
||||||
|
|
||||||
|
// Add adds a value to these extensions
|
||||||
|
func (e Extensions) Add(key string, value interface{}) {
|
||||||
|
realKey := strings.ToLower(key)
|
||||||
|
e[realKey] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetString gets a string value from the extensions
|
||||||
|
func (e Extensions) GetString(key string) (string, bool) {
|
||||||
|
if v, ok := e[strings.ToLower(key)]; ok {
|
||||||
|
str, ok := v.(string)
|
||||||
|
return str, ok
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInt gets a int value from the extensions
|
||||||
|
func (e Extensions) GetInt(key string) (int, bool) {
|
||||||
|
realKey := strings.ToLower(key)
|
||||||
|
|
||||||
|
if v, ok := e.GetString(realKey); ok {
|
||||||
|
if r, err := strconv.Atoi(v); err == nil {
|
||||||
|
return r, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := e[realKey]; ok {
|
||||||
|
if r, rOk := v.(float64); rOk {
|
||||||
|
return int(r), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBool gets a string value from the extensions
|
||||||
|
func (e Extensions) GetBool(key string) (bool, bool) {
|
||||||
|
if v, ok := e[strings.ToLower(key)]; ok {
|
||||||
|
str, ok := v.(bool)
|
||||||
|
return str, ok
|
||||||
|
}
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStringSlice gets a string value from the extensions
|
||||||
|
func (e Extensions) GetStringSlice(key string) ([]string, bool) {
|
||||||
|
if v, ok := e[strings.ToLower(key)]; ok {
|
||||||
|
arr, isSlice := v.([]interface{})
|
||||||
|
if !isSlice {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
var strs []string
|
||||||
|
for _, iface := range arr {
|
||||||
|
str, isString := iface.(string)
|
||||||
|
if !isString {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
strs = append(strs, str)
|
||||||
|
}
|
||||||
|
return strs, ok
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// VendorExtensible composition block.
|
||||||
|
type VendorExtensible struct {
|
||||||
|
Extensions Extensions
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddExtension adds an extension to this extensible object
|
||||||
|
func (v *VendorExtensible) AddExtension(key string, value interface{}) {
|
||||||
|
if value == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v.Extensions == nil {
|
||||||
|
v.Extensions = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
v.Extensions.Add(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshals the extensions to json
|
||||||
|
func (v VendorExtensible) MarshalJSON() ([]byte, error) {
|
||||||
|
toser := make(map[string]interface{})
|
||||||
|
for k, v := range v.Extensions {
|
||||||
|
lk := strings.ToLower(k)
|
||||||
|
if strings.HasPrefix(lk, "x-") {
|
||||||
|
toser[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json.Marshal(toser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON for this extensible object
|
||||||
|
func (v *VendorExtensible) UnmarshalJSON(data []byte) error {
|
||||||
|
var d map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &d); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for k, vv := range d {
|
||||||
|
lk := strings.ToLower(k)
|
||||||
|
if strings.HasPrefix(lk, "x-") {
|
||||||
|
if v.Extensions == nil {
|
||||||
|
v.Extensions = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
v.Extensions[k] = vv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InfoProps the properties for an info definition
|
||||||
|
type InfoProps struct {
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
TermsOfService string `json:"termsOfService,omitempty"`
|
||||||
|
Contact *ContactInfo `json:"contact,omitempty"`
|
||||||
|
License *License `json:"license,omitempty"`
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info object provides metadata about the API.
|
||||||
|
// The metadata can be used by the clients if needed, and can be presented in the Swagger-UI for convenience.
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#infoObject
|
||||||
|
type Info struct {
|
||||||
|
VendorExtensible
|
||||||
|
InfoProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONLookup look up a value by the json property name
|
||||||
|
func (i Info) JSONLookup(token string) (interface{}, error) {
|
||||||
|
if ex, ok := i.Extensions[token]; ok {
|
||||||
|
return &ex, nil
|
||||||
|
}
|
||||||
|
r, _, err := jsonpointer.GetForToken(i.InfoProps, token)
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshal this to JSON
|
||||||
|
func (i Info) MarshalJSON() ([]byte, error) {
|
||||||
|
b1, err := json.Marshal(i.InfoProps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b2, err := json.Marshal(i.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return swag.ConcatJSON(b1, b2), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON marshal this from JSON
|
||||||
|
func (i *Info) UnmarshalJSON(data []byte) error {
|
||||||
|
if err := json.Unmarshal(data, &i.InfoProps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, &i.VendorExtensible)
|
||||||
|
}
|
|
@ -0,0 +1,234 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-openapi/jsonpointer"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
jsonRef = "$ref"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SimpleSchema describe swagger simple schemas for parameters and headers
|
||||||
|
type SimpleSchema struct {
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Nullable bool `json:"nullable,omitempty"`
|
||||||
|
Format string `json:"format,omitempty"`
|
||||||
|
Items *Items `json:"items,omitempty"`
|
||||||
|
CollectionFormat string `json:"collectionFormat,omitempty"`
|
||||||
|
Default interface{} `json:"default,omitempty"`
|
||||||
|
Example interface{} `json:"example,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeName return the type (or format) of a simple schema
|
||||||
|
func (s *SimpleSchema) TypeName() string {
|
||||||
|
if s.Format != "" {
|
||||||
|
return s.Format
|
||||||
|
}
|
||||||
|
return s.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// ItemsTypeName yields the type of items in a simple schema array
|
||||||
|
func (s *SimpleSchema) ItemsTypeName() string {
|
||||||
|
if s.Items == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return s.Items.TypeName()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Items a limited subset of JSON-Schema's items object.
|
||||||
|
// It is used by parameter definitions that are not located in "body".
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#items-object
|
||||||
|
type Items struct {
|
||||||
|
Refable
|
||||||
|
CommonValidations
|
||||||
|
SimpleSchema
|
||||||
|
VendorExtensible
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewItems creates a new instance of items
|
||||||
|
func NewItems() *Items {
|
||||||
|
return &Items{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typed a fluent builder method for the type of item
|
||||||
|
func (i *Items) Typed(tpe, format string) *Items {
|
||||||
|
i.Type = tpe
|
||||||
|
i.Format = format
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsNullable flags this schema as nullable.
|
||||||
|
func (i *Items) AsNullable() *Items {
|
||||||
|
i.Nullable = true
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// CollectionOf a fluent builder method for an array item
|
||||||
|
func (i *Items) CollectionOf(items *Items, format string) *Items {
|
||||||
|
i.Type = jsonArray
|
||||||
|
i.Items = items
|
||||||
|
i.CollectionFormat = format
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDefault sets the default value on this item
|
||||||
|
func (i *Items) WithDefault(defaultValue interface{}) *Items {
|
||||||
|
i.Default = defaultValue
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxLength sets a max length value
|
||||||
|
func (i *Items) WithMaxLength(max int64) *Items {
|
||||||
|
i.MaxLength = &max
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinLength sets a min length value
|
||||||
|
func (i *Items) WithMinLength(min int64) *Items {
|
||||||
|
i.MinLength = &min
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPattern sets a pattern value
|
||||||
|
func (i *Items) WithPattern(pattern string) *Items {
|
||||||
|
i.Pattern = pattern
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMultipleOf sets a multiple of value
|
||||||
|
func (i *Items) WithMultipleOf(number float64) *Items {
|
||||||
|
i.MultipleOf = &number
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaximum sets a maximum number value
|
||||||
|
func (i *Items) WithMaximum(max float64, exclusive bool) *Items {
|
||||||
|
i.Maximum = &max
|
||||||
|
i.ExclusiveMaximum = exclusive
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinimum sets a minimum number value
|
||||||
|
func (i *Items) WithMinimum(min float64, exclusive bool) *Items {
|
||||||
|
i.Minimum = &min
|
||||||
|
i.ExclusiveMinimum = exclusive
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEnum sets a the enum values (replace)
|
||||||
|
func (i *Items) WithEnum(values ...interface{}) *Items {
|
||||||
|
i.Enum = append([]interface{}{}, values...)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxItems sets the max items
|
||||||
|
func (i *Items) WithMaxItems(size int64) *Items {
|
||||||
|
i.MaxItems = &size
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinItems sets the min items
|
||||||
|
func (i *Items) WithMinItems(size int64) *Items {
|
||||||
|
i.MinItems = &size
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// UniqueValues dictates that this array can only have unique items
|
||||||
|
func (i *Items) UniqueValues() *Items {
|
||||||
|
i.UniqueItems = true
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowDuplicates this array can have duplicates
|
||||||
|
func (i *Items) AllowDuplicates() *Items {
|
||||||
|
i.UniqueItems = false
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithValidations is a fluent method to set Items validations
|
||||||
|
func (i *Items) WithValidations(val CommonValidations) *Items {
|
||||||
|
i.SetValidations(SchemaValidations{CommonValidations: val})
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||||
|
func (i *Items) UnmarshalJSON(data []byte) error {
|
||||||
|
var validations CommonValidations
|
||||||
|
if err := json.Unmarshal(data, &validations); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var ref Refable
|
||||||
|
if err := json.Unmarshal(data, &ref); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var simpleSchema SimpleSchema
|
||||||
|
if err := json.Unmarshal(data, &simpleSchema); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var vendorExtensible VendorExtensible
|
||||||
|
if err := json.Unmarshal(data, &vendorExtensible); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.Refable = ref
|
||||||
|
i.CommonValidations = validations
|
||||||
|
i.SimpleSchema = simpleSchema
|
||||||
|
i.VendorExtensible = vendorExtensible
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON converts this items object to JSON
|
||||||
|
func (i Items) MarshalJSON() ([]byte, error) {
|
||||||
|
b1, err := json.Marshal(i.CommonValidations)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b2, err := json.Marshal(i.SimpleSchema)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b3, err := json.Marshal(i.Refable)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b4, err := json.Marshal(i.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return swag.ConcatJSON(b4, b3, b1, b2), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONLookup look up a value by the json property name
|
||||||
|
func (i Items) JSONLookup(token string) (interface{}, error) {
|
||||||
|
if token == jsonRef {
|
||||||
|
return &i.Ref, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r, _, err := jsonpointer.GetForToken(i.CommonValidations, token)
|
||||||
|
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r != nil {
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
r, _, err = jsonpointer.GetForToken(i.SimpleSchema, token)
|
||||||
|
return r, err
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// License information for the exposed API.
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#licenseObject
|
||||||
|
type License struct {
|
||||||
|
LicenseProps
|
||||||
|
VendorExtensible
|
||||||
|
}
|
||||||
|
|
||||||
|
// LicenseProps holds the properties of a License object
|
||||||
|
type LicenseProps struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON hydrates License from json
|
||||||
|
func (l *License) UnmarshalJSON(data []byte) error {
|
||||||
|
if err := json.Unmarshal(data, &l.LicenseProps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, &l.VendorExtensible)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON produces License as json
|
||||||
|
func (l License) MarshalJSON() ([]byte, error) {
|
||||||
|
b1, err := json.Marshal(l.LicenseProps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b2, err := json.Marshal(l.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return swag.ConcatJSON(b1, b2), nil
|
||||||
|
}
|
|
@ -0,0 +1,202 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const fileScheme = "file"
|
||||||
|
|
||||||
|
// normalizeURI ensures that all $ref paths used internally by the expander are canonicalized.
|
||||||
|
//
|
||||||
|
// NOTE(windows): there is a tolerance over the strict URI format on windows.
|
||||||
|
//
|
||||||
|
// The normalizer accepts relative file URLs like 'Path\File.JSON' as well as absolute file URLs like
|
||||||
|
// 'C:\Path\file.Yaml'.
|
||||||
|
//
|
||||||
|
// Both are canonicalized with a "file://" scheme, slashes and a lower-cased path:
|
||||||
|
// 'file:///c:/path/file.yaml'
|
||||||
|
//
|
||||||
|
// URLs can be specified with a file scheme, like in 'file:///folder/file.json' or
|
||||||
|
// 'file:///c:\folder\File.json'.
|
||||||
|
//
|
||||||
|
// URLs like file://C:\folder are considered invalid (i.e. there is no host 'c:\folder') and a "repair"
|
||||||
|
// is attempted.
|
||||||
|
//
|
||||||
|
// The base path argument is assumed to be canonicalized (e.g. using normalizeBase()).
|
||||||
|
func normalizeURI(refPath, base string) string {
|
||||||
|
refURL, err := parseURL(refPath)
|
||||||
|
if err != nil {
|
||||||
|
specLogger.Printf("warning: invalid URI in $ref %q: %v", refPath, err)
|
||||||
|
refURL, refPath = repairURI(refPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
fixWindowsURI(refURL, refPath) // noop on non-windows OS
|
||||||
|
|
||||||
|
refURL.Path = path.Clean(refURL.Path)
|
||||||
|
if refURL.Path == "." {
|
||||||
|
refURL.Path = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
r := MustCreateRef(refURL.String())
|
||||||
|
if r.IsCanonical() {
|
||||||
|
return refURL.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
baseURL, _ := parseURL(base)
|
||||||
|
if path.IsAbs(refURL.Path) {
|
||||||
|
baseURL.Path = refURL.Path
|
||||||
|
} else if refURL.Path != "" {
|
||||||
|
baseURL.Path = path.Join(path.Dir(baseURL.Path), refURL.Path)
|
||||||
|
}
|
||||||
|
// copying fragment from ref to base
|
||||||
|
baseURL.Fragment = refURL.Fragment
|
||||||
|
|
||||||
|
return baseURL.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// denormalizeRef returns the simplest notation for a normalized $ref, given the path of the original root document.
|
||||||
|
//
|
||||||
|
// When calling this, we assume that:
|
||||||
|
// * $ref is a canonical URI
|
||||||
|
// * originalRelativeBase is a canonical URI
|
||||||
|
//
|
||||||
|
// denormalizeRef is currently used when we rewrite a $ref after a circular $ref has been detected.
|
||||||
|
// In this case, expansion stops and normally renders the internal canonical $ref.
|
||||||
|
//
|
||||||
|
// This internal $ref is eventually rebased to the original RelativeBase used for the expansion.
|
||||||
|
//
|
||||||
|
// There is a special case for schemas that are anchored with an "id":
|
||||||
|
// in that case, the rebasing is performed // against the id only if this is an anchor for the initial root document.
|
||||||
|
// All other intermediate "id"'s found along the way are ignored for the purpose of rebasing.
|
||||||
|
func denormalizeRef(ref *Ref, originalRelativeBase, id string) Ref {
|
||||||
|
debugLog("denormalizeRef called:\n$ref: %q\noriginal: %s\nroot ID:%s", ref.String(), originalRelativeBase, id)
|
||||||
|
|
||||||
|
if ref.String() == "" || ref.IsRoot() || ref.HasFragmentOnly {
|
||||||
|
// short circuit: $ref to current doc
|
||||||
|
return *ref
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != "" {
|
||||||
|
idBaseURL, err := parseURL(id)
|
||||||
|
if err == nil { // if the schema id is not usable as a URI, ignore it
|
||||||
|
if ref, ok := rebase(ref, idBaseURL, true); ok { // rebase, but keep references to root unchaged (do not want $ref: "")
|
||||||
|
// $ref relative to the ID of the schema in the root document
|
||||||
|
return ref
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
originalRelativeBaseURL, _ := parseURL(originalRelativeBase)
|
||||||
|
|
||||||
|
r, _ := rebase(ref, originalRelativeBaseURL, false)
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func rebase(ref *Ref, v *url.URL, notEqual bool) (Ref, bool) {
|
||||||
|
var newBase url.URL
|
||||||
|
|
||||||
|
u := ref.GetURL()
|
||||||
|
|
||||||
|
if u.Scheme != v.Scheme || u.Host != v.Host {
|
||||||
|
return *ref, false
|
||||||
|
}
|
||||||
|
|
||||||
|
docPath := v.Path
|
||||||
|
v.Path = path.Dir(v.Path)
|
||||||
|
|
||||||
|
if v.Path == "." {
|
||||||
|
v.Path = ""
|
||||||
|
} else if !strings.HasSuffix(v.Path, "/") {
|
||||||
|
v.Path += "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
newBase.Fragment = u.Fragment
|
||||||
|
|
||||||
|
if strings.HasPrefix(u.Path, docPath) {
|
||||||
|
newBase.Path = strings.TrimPrefix(u.Path, docPath)
|
||||||
|
} else {
|
||||||
|
newBase.Path = strings.TrimPrefix(u.Path, v.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if notEqual && newBase.Path == "" && newBase.Fragment == "" {
|
||||||
|
// do not want rebasing to end up in an empty $ref
|
||||||
|
return *ref, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if path.IsAbs(newBase.Path) {
|
||||||
|
// whenever we end up with an absolute path, specify the scheme and host
|
||||||
|
newBase.Scheme = v.Scheme
|
||||||
|
newBase.Host = v.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
return MustCreateRef(newBase.String()), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizeRef canonicalize a Ref, using a canonical relativeBase as its absolute anchor
|
||||||
|
func normalizeRef(ref *Ref, relativeBase string) *Ref {
|
||||||
|
r := MustCreateRef(normalizeURI(ref.String(), relativeBase))
|
||||||
|
return &r
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizeBase performs a normalization of the input base path.
|
||||||
|
//
|
||||||
|
// This always yields a canonical URI (absolute), usable for the document cache.
|
||||||
|
//
|
||||||
|
// It ensures that all further internal work on basePath may safely assume
|
||||||
|
// a non-empty, cross-platform, canonical URI (i.e. absolute).
|
||||||
|
//
|
||||||
|
// This normalization tolerates windows paths (e.g. C:\x\y\File.dat) and transform this
|
||||||
|
// in a file:// URL with lower cased drive letter and path.
|
||||||
|
//
|
||||||
|
// See also: https://en.wikipedia.org/wiki/File_URI_scheme
|
||||||
|
func normalizeBase(in string) string {
|
||||||
|
u, err := parseURL(in)
|
||||||
|
if err != nil {
|
||||||
|
specLogger.Printf("warning: invalid URI in RelativeBase %q: %v", in, err)
|
||||||
|
u, in = repairURI(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
u.Fragment = "" // any fragment in the base is irrelevant
|
||||||
|
|
||||||
|
fixWindowsURI(u, in) // noop on non-windows OS
|
||||||
|
|
||||||
|
u.Path = path.Clean(u.Path)
|
||||||
|
if u.Path == "." { // empty after Clean()
|
||||||
|
u.Path = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Scheme != "" {
|
||||||
|
if path.IsAbs(u.Path) || u.Scheme != fileScheme {
|
||||||
|
// this is absolute or explicitly not a local file: we're good
|
||||||
|
return u.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no scheme or file scheme with relative path: assume file and make it absolute
|
||||||
|
// enforce scheme file://... with absolute path.
|
||||||
|
//
|
||||||
|
// If the input path is relative, we anchor the path to the current working directory.
|
||||||
|
// NOTE: we may end up with a host component. Leave it unchanged: e.g. file://host/folder/file.json
|
||||||
|
|
||||||
|
u.Scheme = fileScheme
|
||||||
|
u.Path = absPath(u.Path) // platform-dependent
|
||||||
|
u.RawQuery = "" // any query component is irrelevant for a base
|
||||||
|
return u.String()
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// absPath makes a file path absolute and compatible with a URI path component.
|
||||||
|
//
|
||||||
|
// The parameter must be a path, not an URI.
|
||||||
|
func absPath(in string) string {
|
||||||
|
anchored, err := filepath.Abs(in)
|
||||||
|
if err != nil {
|
||||||
|
specLogger.Printf("warning: could not resolve current working directory: %v", err)
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
return anchored
|
||||||
|
}
|
||||||
|
|
||||||
|
func repairURI(in string) (*url.URL, string) {
|
||||||
|
u, _ := parseURL("")
|
||||||
|
debugLog("repaired URI: original: %q, repaired: %q", in, "")
|
||||||
|
return u, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func fixWindowsURI(_ *url.URL, _ string) {
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
// -build windows
|
||||||
|
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// absPath makes a file path absolute and compatible with a URI path component
|
||||||
|
//
|
||||||
|
// The parameter must be a path, not an URI.
|
||||||
|
func absPath(in string) string {
|
||||||
|
// NOTE(windows): filepath.Abs exhibits a special behavior on windows for empty paths.
|
||||||
|
// See https://github.com/golang/go/issues/24441
|
||||||
|
if in == "" {
|
||||||
|
in = "."
|
||||||
|
}
|
||||||
|
|
||||||
|
anchored, err := filepath.Abs(in)
|
||||||
|
if err != nil {
|
||||||
|
specLogger.Printf("warning: could not resolve current working directory: %v", err)
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
|
||||||
|
pth := strings.ReplaceAll(strings.ToLower(anchored), `\`, `/`)
|
||||||
|
if !strings.HasPrefix(pth, "/") {
|
||||||
|
pth = "/" + pth
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.Clean(pth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// repairURI tolerates invalid file URIs with common typos
|
||||||
|
// such as 'file://E:\folder\file', that break the regular URL parser.
|
||||||
|
//
|
||||||
|
// Adopting the same defaults as for unixes (e.g. return an empty path) would
|
||||||
|
// result into a counter-intuitive result for that case (e.g. E:\folder\file is
|
||||||
|
// eventually resolved as the current directory). The repair will detect the missing "/".
|
||||||
|
//
|
||||||
|
// Note that this only works for the file scheme.
|
||||||
|
func repairURI(in string) (*url.URL, string) {
|
||||||
|
const prefix = fileScheme + "://"
|
||||||
|
if !strings.HasPrefix(in, prefix) {
|
||||||
|
// giving up: resolve to empty path
|
||||||
|
u, _ := parseURL("")
|
||||||
|
|
||||||
|
return u, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// attempt the repair, stripping the scheme should be sufficient
|
||||||
|
u, _ := parseURL(strings.TrimPrefix(in, prefix))
|
||||||
|
debugLog("repaired URI: original: %q, repaired: %q", in, u.String())
|
||||||
|
|
||||||
|
return u, u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixWindowsURI tolerates an absolute file path on windows such as C:\Base\File.yaml or \\host\share\Base\File.yaml
|
||||||
|
// and makes it a canonical URI: file:///c:/base/file.yaml
|
||||||
|
//
|
||||||
|
// Catch 22 notes for Windows:
|
||||||
|
//
|
||||||
|
// * There may be a drive letter on windows (it is lower-cased)
|
||||||
|
// * There may be a share UNC, e.g. \\server\folder\data.xml
|
||||||
|
// * Paths are case insensitive
|
||||||
|
// * Paths may already contain slashes
|
||||||
|
// * Paths must be slashed
|
||||||
|
//
|
||||||
|
// NOTE: there is no escaping. "/" may be valid separators just like "\".
|
||||||
|
// We don't use ToSlash() (which escapes everything) because windows now also
|
||||||
|
// tolerates the use of "/". Hence, both C:\File.yaml and C:/File.yaml will work.
|
||||||
|
func fixWindowsURI(u *url.URL, in string) {
|
||||||
|
drive := filepath.VolumeName(in)
|
||||||
|
|
||||||
|
if len(drive) > 0 {
|
||||||
|
if len(u.Scheme) == 1 && strings.EqualFold(u.Scheme, drive[:1]) { // a path with a drive letter
|
||||||
|
u.Scheme = fileScheme
|
||||||
|
u.Host = ""
|
||||||
|
u.Path = strings.Join([]string{drive, u.Opaque, u.Path}, `/`) // reconstruct the full path component (no fragment, no query)
|
||||||
|
} else if u.Host == "" && strings.HasPrefix(u.Path, drive) { // a path with a \\host volume
|
||||||
|
// NOTE: the special host@port syntax for UNC is not supported (yet)
|
||||||
|
u.Scheme = fileScheme
|
||||||
|
|
||||||
|
// this is a modified version of filepath.Dir() to apply on the VolumeName itself
|
||||||
|
i := len(drive) - 1
|
||||||
|
for i >= 0 && !os.IsPathSeparator(drive[i]) {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
host := drive[:i] // \\host\share => host
|
||||||
|
|
||||||
|
u.Path = strings.TrimPrefix(u.Path, host)
|
||||||
|
u.Host = strings.TrimPrefix(host, `\\`)
|
||||||
|
}
|
||||||
|
|
||||||
|
u.Opaque = ""
|
||||||
|
u.Path = strings.ReplaceAll(strings.ToLower(u.Path), `\`, `/`)
|
||||||
|
|
||||||
|
// ensure we form an absolute path
|
||||||
|
if !strings.HasPrefix(u.Path, "/") {
|
||||||
|
u.Path = "/" + u.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
u.Path = path.Clean(u.Path)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Scheme == fileScheme {
|
||||||
|
// Handle dodgy cases for file://{...} URIs on windows.
|
||||||
|
// A canonical URI should always be followed by an absolute path.
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
// * file:///folder/file => valid, unchanged
|
||||||
|
// * file:///c:\folder\file => slashed
|
||||||
|
// * file:///./folder/file => valid, cleaned to remove the dot
|
||||||
|
// * file:///.\folder\file => remapped to cwd
|
||||||
|
// * file:///. => dodgy, remapped to / (consistent with the behavior on unix)
|
||||||
|
// * file:///.. => dodgy, remapped to / (consistent with the behavior on unix)
|
||||||
|
if (!path.IsAbs(u.Path) && !filepath.IsAbs(u.Path)) || (strings.HasPrefix(u.Path, `/.`) && strings.Contains(u.Path, `\`)) {
|
||||||
|
// ensure we form an absolute path
|
||||||
|
u.Path, _ = filepath.Abs(strings.TrimLeft(u.Path, `/`))
|
||||||
|
if !strings.HasPrefix(u.Path, "/") {
|
||||||
|
u.Path = "/" + u.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u.Path = strings.ToLower(u.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: lower case normalization does not propagate to inner resources,
|
||||||
|
// generated when rebasing: when joining a relative URI with a file to an absolute base,
|
||||||
|
// only the base is currently lower-cased.
|
||||||
|
//
|
||||||
|
// For now, we assume this is good enough for most use cases
|
||||||
|
// and try not to generate too many differences
|
||||||
|
// between the output produced on different platforms.
|
||||||
|
u.Path = path.Clean(strings.ReplaceAll(u.Path, `\`, `/`))
|
||||||
|
}
|
|
@ -0,0 +1,400 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
"encoding/json"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/go-openapi/jsonpointer"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gob.Register(map[string]interface{}{})
|
||||||
|
gob.Register([]interface{}{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// OperationProps describes an operation
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
// - schemes, when present must be from [http, https, ws, wss]: see validate
|
||||||
|
// - Security is handled as a special case: see MarshalJSON function
|
||||||
|
type OperationProps struct {
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Consumes []string `json:"consumes,omitempty"`
|
||||||
|
Produces []string `json:"produces,omitempty"`
|
||||||
|
Schemes []string `json:"schemes,omitempty"`
|
||||||
|
Tags []string `json:"tags,omitempty"`
|
||||||
|
Summary string `json:"summary,omitempty"`
|
||||||
|
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||||
|
ID string `json:"operationId,omitempty"`
|
||||||
|
Deprecated bool `json:"deprecated,omitempty"`
|
||||||
|
Security []map[string][]string `json:"security,omitempty"`
|
||||||
|
Parameters []Parameter `json:"parameters,omitempty"`
|
||||||
|
Responses *Responses `json:"responses,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON takes care of serializing operation properties to JSON
|
||||||
|
//
|
||||||
|
// We use a custom marhaller here to handle a special cases related to
|
||||||
|
// the Security field. We need to preserve zero length slice
|
||||||
|
// while omitting the field when the value is nil/unset.
|
||||||
|
func (op OperationProps) MarshalJSON() ([]byte, error) {
|
||||||
|
type Alias OperationProps
|
||||||
|
if op.Security == nil {
|
||||||
|
return json.Marshal(&struct {
|
||||||
|
Security []map[string][]string `json:"security,omitempty"`
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Security: op.Security,
|
||||||
|
Alias: (*Alias)(&op),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return json.Marshal(&struct {
|
||||||
|
Security []map[string][]string `json:"security"`
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Security: op.Security,
|
||||||
|
Alias: (*Alias)(&op),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operation describes a single API operation on a path.
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#operationObject
|
||||||
|
type Operation struct {
|
||||||
|
VendorExtensible
|
||||||
|
OperationProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// SuccessResponse gets a success response model
|
||||||
|
func (o *Operation) SuccessResponse() (*Response, int, bool) {
|
||||||
|
if o.Responses == nil {
|
||||||
|
return nil, 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
responseCodes := make([]int, 0, len(o.Responses.StatusCodeResponses))
|
||||||
|
for k := range o.Responses.StatusCodeResponses {
|
||||||
|
if k >= 200 && k < 300 {
|
||||||
|
responseCodes = append(responseCodes, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(responseCodes) > 0 {
|
||||||
|
sort.Ints(responseCodes)
|
||||||
|
v := o.Responses.StatusCodeResponses[responseCodes[0]]
|
||||||
|
return &v, responseCodes[0], true
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.Responses.Default, 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONLookup look up a value by the json property name
|
||||||
|
func (o Operation) JSONLookup(token string) (interface{}, error) {
|
||||||
|
if ex, ok := o.Extensions[token]; ok {
|
||||||
|
return &ex, nil
|
||||||
|
}
|
||||||
|
r, _, err := jsonpointer.GetForToken(o.OperationProps, token)
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||||
|
func (o *Operation) UnmarshalJSON(data []byte) error {
|
||||||
|
if err := json.Unmarshal(data, &o.OperationProps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, &o.VendorExtensible)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON converts this items object to JSON
|
||||||
|
func (o Operation) MarshalJSON() ([]byte, error) {
|
||||||
|
b1, err := json.Marshal(o.OperationProps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b2, err := json.Marshal(o.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
concated := swag.ConcatJSON(b1, b2)
|
||||||
|
return concated, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOperation creates a new operation instance.
|
||||||
|
// It expects an ID as parameter but not passing an ID is also valid.
|
||||||
|
func NewOperation(id string) *Operation {
|
||||||
|
op := new(Operation)
|
||||||
|
op.ID = id
|
||||||
|
return op
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithID sets the ID property on this operation, allows for chaining.
|
||||||
|
func (o *Operation) WithID(id string) *Operation {
|
||||||
|
o.ID = id
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDescription sets the description on this operation, allows for chaining
|
||||||
|
func (o *Operation) WithDescription(description string) *Operation {
|
||||||
|
o.Description = description
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSummary sets the summary on this operation, allows for chaining
|
||||||
|
func (o *Operation) WithSummary(summary string) *Operation {
|
||||||
|
o.Summary = summary
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithExternalDocs sets/removes the external docs for/from this operation.
|
||||||
|
// When you pass empty strings as params the external documents will be removed.
|
||||||
|
// When you pass non-empty string as one value then those values will be used on the external docs object.
|
||||||
|
// So when you pass a non-empty description, you should also pass the url and vice versa.
|
||||||
|
func (o *Operation) WithExternalDocs(description, url string) *Operation {
|
||||||
|
if description == "" && url == "" {
|
||||||
|
o.ExternalDocs = nil
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.ExternalDocs == nil {
|
||||||
|
o.ExternalDocs = &ExternalDocumentation{}
|
||||||
|
}
|
||||||
|
o.ExternalDocs.Description = description
|
||||||
|
o.ExternalDocs.URL = url
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecate marks the operation as deprecated
|
||||||
|
func (o *Operation) Deprecate() *Operation {
|
||||||
|
o.Deprecated = true
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// Undeprecate marks the operation as not deprected
|
||||||
|
func (o *Operation) Undeprecate() *Operation {
|
||||||
|
o.Deprecated = false
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithConsumes adds media types for incoming body values
|
||||||
|
func (o *Operation) WithConsumes(mediaTypes ...string) *Operation {
|
||||||
|
o.Consumes = append(o.Consumes, mediaTypes...)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithProduces adds media types for outgoing body values
|
||||||
|
func (o *Operation) WithProduces(mediaTypes ...string) *Operation {
|
||||||
|
o.Produces = append(o.Produces, mediaTypes...)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTags adds tags for this operation
|
||||||
|
func (o *Operation) WithTags(tags ...string) *Operation {
|
||||||
|
o.Tags = append(o.Tags, tags...)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddParam adds a parameter to this operation, when a parameter for that location
|
||||||
|
// and with that name already exists it will be replaced
|
||||||
|
func (o *Operation) AddParam(param *Parameter) *Operation {
|
||||||
|
if param == nil {
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, p := range o.Parameters {
|
||||||
|
if p.Name == param.Name && p.In == param.In {
|
||||||
|
params := make([]Parameter, 0, len(o.Parameters)+1)
|
||||||
|
params = append(params, o.Parameters[:i]...)
|
||||||
|
params = append(params, *param)
|
||||||
|
params = append(params, o.Parameters[i+1:]...)
|
||||||
|
o.Parameters = params
|
||||||
|
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
o.Parameters = append(o.Parameters, *param)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveParam removes a parameter from the operation
|
||||||
|
func (o *Operation) RemoveParam(name, in string) *Operation {
|
||||||
|
for i, p := range o.Parameters {
|
||||||
|
if p.Name == name && p.In == in {
|
||||||
|
o.Parameters = append(o.Parameters[:i], o.Parameters[i+1:]...)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecuredWith adds a security scope to this operation.
|
||||||
|
func (o *Operation) SecuredWith(name string, scopes ...string) *Operation {
|
||||||
|
o.Security = append(o.Security, map[string][]string{name: scopes})
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDefaultResponse adds a default response to the operation.
|
||||||
|
// Passing a nil value will remove the response
|
||||||
|
func (o *Operation) WithDefaultResponse(response *Response) *Operation {
|
||||||
|
return o.RespondsWith(0, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RespondsWith adds a status code response to the operation.
|
||||||
|
// When the code is 0 the value of the response will be used as default response value.
|
||||||
|
// When the value of the response is nil it will be removed from the operation
|
||||||
|
func (o *Operation) RespondsWith(code int, response *Response) *Operation {
|
||||||
|
if o.Responses == nil {
|
||||||
|
o.Responses = new(Responses)
|
||||||
|
}
|
||||||
|
if code == 0 {
|
||||||
|
o.Responses.Default = response
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
if response == nil {
|
||||||
|
delete(o.Responses.StatusCodeResponses, code)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
if o.Responses.StatusCodeResponses == nil {
|
||||||
|
o.Responses.StatusCodeResponses = make(map[int]Response)
|
||||||
|
}
|
||||||
|
o.Responses.StatusCodeResponses[code] = *response
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
type opsAlias OperationProps
|
||||||
|
|
||||||
|
type gobAlias struct {
|
||||||
|
Security []map[string]struct {
|
||||||
|
List []string
|
||||||
|
Pad bool
|
||||||
|
}
|
||||||
|
Alias *opsAlias
|
||||||
|
SecurityIsEmpty bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// GobEncode provides a safe gob encoder for Operation, including empty security requirements
|
||||||
|
func (o Operation) GobEncode() ([]byte, error) {
|
||||||
|
raw := struct {
|
||||||
|
Ext VendorExtensible
|
||||||
|
Props OperationProps
|
||||||
|
}{
|
||||||
|
Ext: o.VendorExtensible,
|
||||||
|
Props: o.OperationProps,
|
||||||
|
}
|
||||||
|
var b bytes.Buffer
|
||||||
|
err := gob.NewEncoder(&b).Encode(raw)
|
||||||
|
return b.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GobDecode provides a safe gob decoder for Operation, including empty security requirements
|
||||||
|
func (o *Operation) GobDecode(b []byte) error {
|
||||||
|
var raw struct {
|
||||||
|
Ext VendorExtensible
|
||||||
|
Props OperationProps
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
err := gob.NewDecoder(buf).Decode(&raw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
o.VendorExtensible = raw.Ext
|
||||||
|
o.OperationProps = raw.Props
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GobEncode provides a safe gob encoder for Operation, including empty security requirements
|
||||||
|
func (op OperationProps) GobEncode() ([]byte, error) {
|
||||||
|
raw := gobAlias{
|
||||||
|
Alias: (*opsAlias)(&op),
|
||||||
|
}
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
if op.Security == nil {
|
||||||
|
// nil security requirement
|
||||||
|
err := gob.NewEncoder(&b).Encode(raw)
|
||||||
|
return b.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(op.Security) == 0 {
|
||||||
|
// empty, but non-nil security requirement
|
||||||
|
raw.SecurityIsEmpty = true
|
||||||
|
raw.Alias.Security = nil
|
||||||
|
err := gob.NewEncoder(&b).Encode(raw)
|
||||||
|
return b.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
raw.Security = make([]map[string]struct {
|
||||||
|
List []string
|
||||||
|
Pad bool
|
||||||
|
}, 0, len(op.Security))
|
||||||
|
for _, req := range op.Security {
|
||||||
|
v := make(map[string]struct {
|
||||||
|
List []string
|
||||||
|
Pad bool
|
||||||
|
}, len(req))
|
||||||
|
for k, val := range req {
|
||||||
|
v[k] = struct {
|
||||||
|
List []string
|
||||||
|
Pad bool
|
||||||
|
}{
|
||||||
|
List: val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
raw.Security = append(raw.Security, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := gob.NewEncoder(&b).Encode(raw)
|
||||||
|
return b.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GobDecode provides a safe gob decoder for Operation, including empty security requirements
|
||||||
|
func (op *OperationProps) GobDecode(b []byte) error {
|
||||||
|
var raw gobAlias
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
err := gob.NewDecoder(buf).Decode(&raw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if raw.Alias == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case raw.SecurityIsEmpty:
|
||||||
|
// empty, but non-nil security requirement
|
||||||
|
raw.Alias.Security = []map[string][]string{}
|
||||||
|
case len(raw.Alias.Security) == 0:
|
||||||
|
// nil security requirement
|
||||||
|
raw.Alias.Security = nil
|
||||||
|
default:
|
||||||
|
raw.Alias.Security = make([]map[string][]string, 0, len(raw.Security))
|
||||||
|
for _, req := range raw.Security {
|
||||||
|
v := make(map[string][]string, len(req))
|
||||||
|
for k, val := range req {
|
||||||
|
v[k] = make([]string, 0, len(val.List))
|
||||||
|
v[k] = append(v[k], val.List...)
|
||||||
|
}
|
||||||
|
raw.Alias.Security = append(raw.Alias.Security, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*op = *(*OperationProps)(raw.Alias)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,326 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-openapi/jsonpointer"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// QueryParam creates a query parameter
|
||||||
|
func QueryParam(name string) *Parameter {
|
||||||
|
return &Parameter{ParamProps: ParamProps{Name: name, In: "query"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeaderParam creates a header parameter, this is always required by default
|
||||||
|
func HeaderParam(name string) *Parameter {
|
||||||
|
return &Parameter{ParamProps: ParamProps{Name: name, In: "header", Required: true}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathParam creates a path parameter, this is always required
|
||||||
|
func PathParam(name string) *Parameter {
|
||||||
|
return &Parameter{ParamProps: ParamProps{Name: name, In: "path", Required: true}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyParam creates a body parameter
|
||||||
|
func BodyParam(name string, schema *Schema) *Parameter {
|
||||||
|
return &Parameter{ParamProps: ParamProps{Name: name, In: "body", Schema: schema}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormDataParam creates a body parameter
|
||||||
|
func FormDataParam(name string) *Parameter {
|
||||||
|
return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileParam creates a body parameter
|
||||||
|
func FileParam(name string) *Parameter {
|
||||||
|
return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"},
|
||||||
|
SimpleSchema: SimpleSchema{Type: "file"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimpleArrayParam creates a param for a simple array (string, int, date etc)
|
||||||
|
func SimpleArrayParam(name, tpe, fmt string) *Parameter {
|
||||||
|
return &Parameter{ParamProps: ParamProps{Name: name},
|
||||||
|
SimpleSchema: SimpleSchema{Type: jsonArray, CollectionFormat: "csv",
|
||||||
|
Items: &Items{SimpleSchema: SimpleSchema{Type: tpe, Format: fmt}}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParamRef creates a parameter that's a json reference
|
||||||
|
func ParamRef(uri string) *Parameter {
|
||||||
|
p := new(Parameter)
|
||||||
|
p.Ref = MustCreateRef(uri)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParamProps describes the specific attributes of an operation parameter
|
||||||
|
//
|
||||||
|
// NOTE:
|
||||||
|
// - Schema is defined when "in" == "body": see validate
|
||||||
|
// - AllowEmptyValue is allowed where "in" == "query" || "formData"
|
||||||
|
type ParamProps struct {
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
In string `json:"in,omitempty"`
|
||||||
|
Required bool `json:"required,omitempty"`
|
||||||
|
Schema *Schema `json:"schema,omitempty"`
|
||||||
|
AllowEmptyValue bool `json:"allowEmptyValue,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parameter a unique parameter is defined by a combination of a [name](#parameterName) and [location](#parameterIn).
|
||||||
|
//
|
||||||
|
// There are five possible parameter types.
|
||||||
|
// - Path - Used together with [Path Templating](#pathTemplating), where the parameter value is actually part
|
||||||
|
// of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`,
|
||||||
|
// the path parameter is `itemId`.
|
||||||
|
// - Query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`.
|
||||||
|
// - Header - Custom headers that are expected as part of the request.
|
||||||
|
// - Body - The payload that's appended to the HTTP request. Since there can only be one payload, there can only be
|
||||||
|
// _one_ body parameter. The name of the body parameter has no effect on the parameter itself and is used for
|
||||||
|
// documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist
|
||||||
|
// together for the same operation.
|
||||||
|
// - Form - Used to describe the payload of an HTTP request when either `application/x-www-form-urlencoded` or
|
||||||
|
// `multipart/form-data` are used as the content type of the request (in Swagger's definition,
|
||||||
|
// the [`consumes`](#operationConsumes) property of an operation). This is the only parameter type that can be used
|
||||||
|
// to send files, thus supporting the `file` type. Since form parameters are sent in the payload, they cannot be
|
||||||
|
// declared together with a body parameter for the same operation. Form parameters have a different format based on
|
||||||
|
// the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4).
|
||||||
|
// - `application/x-www-form-urlencoded` - Similar to the format of Query parameters but as a payload.
|
||||||
|
// For example, `foo=1&bar=swagger` - both `foo` and `bar` are form parameters. This is normally used for simple
|
||||||
|
// parameters that are being transferred.
|
||||||
|
// - `multipart/form-data` - each parameter takes a section in the payload with an internal header.
|
||||||
|
// For example, for the header `Content-Disposition: form-data; name="submit-name"` the name of the parameter is
|
||||||
|
// `submit-name`. This type of form parameters is more commonly used for file transfers.
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#parameterObject
|
||||||
|
type Parameter struct {
|
||||||
|
Refable
|
||||||
|
CommonValidations
|
||||||
|
SimpleSchema
|
||||||
|
VendorExtensible
|
||||||
|
ParamProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONLookup look up a value by the json property name
|
||||||
|
func (p Parameter) JSONLookup(token string) (interface{}, error) {
|
||||||
|
if ex, ok := p.Extensions[token]; ok {
|
||||||
|
return &ex, nil
|
||||||
|
}
|
||||||
|
if token == jsonRef {
|
||||||
|
return &p.Ref, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r, _, err := jsonpointer.GetForToken(p.CommonValidations, token)
|
||||||
|
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r != nil {
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
r, _, err = jsonpointer.GetForToken(p.SimpleSchema, token)
|
||||||
|
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r != nil {
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
r, _, err = jsonpointer.GetForToken(p.ParamProps, token)
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDescription a fluent builder method for the description of the parameter
|
||||||
|
func (p *Parameter) WithDescription(description string) *Parameter {
|
||||||
|
p.Description = description
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Named a fluent builder method to override the name of the parameter
|
||||||
|
func (p *Parameter) Named(name string) *Parameter {
|
||||||
|
p.Name = name
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLocation a fluent builder method to override the location of the parameter
|
||||||
|
func (p *Parameter) WithLocation(in string) *Parameter {
|
||||||
|
p.In = in
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typed a fluent builder method for the type of the parameter value
|
||||||
|
func (p *Parameter) Typed(tpe, format string) *Parameter {
|
||||||
|
p.Type = tpe
|
||||||
|
p.Format = format
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// CollectionOf a fluent builder method for an array parameter
|
||||||
|
func (p *Parameter) CollectionOf(items *Items, format string) *Parameter {
|
||||||
|
p.Type = jsonArray
|
||||||
|
p.Items = items
|
||||||
|
p.CollectionFormat = format
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDefault sets the default value on this parameter
|
||||||
|
func (p *Parameter) WithDefault(defaultValue interface{}) *Parameter {
|
||||||
|
p.AsOptional() // with default implies optional
|
||||||
|
p.Default = defaultValue
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowsEmptyValues flags this parameter as being ok with empty values
|
||||||
|
func (p *Parameter) AllowsEmptyValues() *Parameter {
|
||||||
|
p.AllowEmptyValue = true
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// NoEmptyValues flags this parameter as not liking empty values
|
||||||
|
func (p *Parameter) NoEmptyValues() *Parameter {
|
||||||
|
p.AllowEmptyValue = false
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsOptional flags this parameter as optional
|
||||||
|
func (p *Parameter) AsOptional() *Parameter {
|
||||||
|
p.Required = false
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsRequired flags this parameter as required
|
||||||
|
func (p *Parameter) AsRequired() *Parameter {
|
||||||
|
if p.Default != nil { // with a default required makes no sense
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
p.Required = true
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxLength sets a max length value
|
||||||
|
func (p *Parameter) WithMaxLength(max int64) *Parameter {
|
||||||
|
p.MaxLength = &max
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinLength sets a min length value
|
||||||
|
func (p *Parameter) WithMinLength(min int64) *Parameter {
|
||||||
|
p.MinLength = &min
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPattern sets a pattern value
|
||||||
|
func (p *Parameter) WithPattern(pattern string) *Parameter {
|
||||||
|
p.Pattern = pattern
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMultipleOf sets a multiple of value
|
||||||
|
func (p *Parameter) WithMultipleOf(number float64) *Parameter {
|
||||||
|
p.MultipleOf = &number
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaximum sets a maximum number value
|
||||||
|
func (p *Parameter) WithMaximum(max float64, exclusive bool) *Parameter {
|
||||||
|
p.Maximum = &max
|
||||||
|
p.ExclusiveMaximum = exclusive
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinimum sets a minimum number value
|
||||||
|
func (p *Parameter) WithMinimum(min float64, exclusive bool) *Parameter {
|
||||||
|
p.Minimum = &min
|
||||||
|
p.ExclusiveMinimum = exclusive
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEnum sets a the enum values (replace)
|
||||||
|
func (p *Parameter) WithEnum(values ...interface{}) *Parameter {
|
||||||
|
p.Enum = append([]interface{}{}, values...)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxItems sets the max items
|
||||||
|
func (p *Parameter) WithMaxItems(size int64) *Parameter {
|
||||||
|
p.MaxItems = &size
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinItems sets the min items
|
||||||
|
func (p *Parameter) WithMinItems(size int64) *Parameter {
|
||||||
|
p.MinItems = &size
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// UniqueValues dictates that this array can only have unique items
|
||||||
|
func (p *Parameter) UniqueValues() *Parameter {
|
||||||
|
p.UniqueItems = true
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowDuplicates this array can have duplicates
|
||||||
|
func (p *Parameter) AllowDuplicates() *Parameter {
|
||||||
|
p.UniqueItems = false
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithValidations is a fluent method to set parameter validations
|
||||||
|
func (p *Parameter) WithValidations(val CommonValidations) *Parameter {
|
||||||
|
p.SetValidations(SchemaValidations{CommonValidations: val})
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||||
|
func (p *Parameter) UnmarshalJSON(data []byte) error {
|
||||||
|
if err := json.Unmarshal(data, &p.CommonValidations); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &p.Refable); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &p.SimpleSchema); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, &p.ParamProps)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON converts this items object to JSON
|
||||||
|
func (p Parameter) MarshalJSON() ([]byte, error) {
|
||||||
|
b1, err := json.Marshal(p.CommonValidations)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b2, err := json.Marshal(p.SimpleSchema)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b3, err := json.Marshal(p.Refable)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b4, err := json.Marshal(p.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b5, err := json.Marshal(p.ParamProps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return swag.ConcatJSON(b3, b1, b2, b4, b5), nil
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/go-openapi/jsonpointer"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PathItemProps the path item specific properties
|
||||||
|
type PathItemProps struct {
|
||||||
|
Get *Operation `json:"get,omitempty"`
|
||||||
|
Put *Operation `json:"put,omitempty"`
|
||||||
|
Post *Operation `json:"post,omitempty"`
|
||||||
|
Delete *Operation `json:"delete,omitempty"`
|
||||||
|
Options *Operation `json:"options,omitempty"`
|
||||||
|
Head *Operation `json:"head,omitempty"`
|
||||||
|
Patch *Operation `json:"patch,omitempty"`
|
||||||
|
Parameters []Parameter `json:"parameters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathItem describes the operations available on a single path.
|
||||||
|
// A Path Item may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
|
||||||
|
// The path itself is still exposed to the documentation viewer but they will
|
||||||
|
// not know which operations and parameters are available.
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#pathItemObject
|
||||||
|
type PathItem struct {
|
||||||
|
Refable
|
||||||
|
VendorExtensible
|
||||||
|
PathItemProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONLookup look up a value by the json property name
|
||||||
|
func (p PathItem) JSONLookup(token string) (interface{}, error) {
|
||||||
|
if ex, ok := p.Extensions[token]; ok {
|
||||||
|
return &ex, nil
|
||||||
|
}
|
||||||
|
if token == jsonRef {
|
||||||
|
return &p.Ref, nil
|
||||||
|
}
|
||||||
|
r, _, err := jsonpointer.GetForToken(p.PathItemProps, token)
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||||
|
func (p *PathItem) UnmarshalJSON(data []byte) error {
|
||||||
|
if err := json.Unmarshal(data, &p.Refable); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, &p.PathItemProps)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON converts this items object to JSON
|
||||||
|
func (p PathItem) MarshalJSON() ([]byte, error) {
|
||||||
|
b3, err := json.Marshal(p.Refable)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b4, err := json.Marshal(p.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b5, err := json.Marshal(p.PathItemProps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
concated := swag.ConcatJSON(b3, b4, b5)
|
||||||
|
return concated, nil
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Paths holds the relative paths to the individual endpoints.
|
||||||
|
// The path is appended to the [`basePath`](http://goo.gl/8us55a#swaggerBasePath) in order
|
||||||
|
// to construct the full URL.
|
||||||
|
// The Paths may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#pathsObject
|
||||||
|
type Paths struct {
|
||||||
|
VendorExtensible
|
||||||
|
Paths map[string]PathItem `json:"-"` // custom serializer to flatten this, each entry must start with "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONLookup look up a value by the json property name
|
||||||
|
func (p Paths) JSONLookup(token string) (interface{}, error) {
|
||||||
|
if pi, ok := p.Paths[token]; ok {
|
||||||
|
return &pi, nil
|
||||||
|
}
|
||||||
|
if ex, ok := p.Extensions[token]; ok {
|
||||||
|
return &ex, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("object has no field %q", token)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||||
|
func (p *Paths) UnmarshalJSON(data []byte) error {
|
||||||
|
var res map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for k, v := range res {
|
||||||
|
if strings.HasPrefix(strings.ToLower(k), "x-") {
|
||||||
|
if p.Extensions == nil {
|
||||||
|
p.Extensions = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
var d interface{}
|
||||||
|
if err := json.Unmarshal(v, &d); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Extensions[k] = d
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(k, "/") {
|
||||||
|
if p.Paths == nil {
|
||||||
|
p.Paths = make(map[string]PathItem)
|
||||||
|
}
|
||||||
|
var pi PathItem
|
||||||
|
if err := json.Unmarshal(v, &pi); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Paths[k] = pi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON converts this items object to JSON
|
||||||
|
func (p Paths) MarshalJSON() ([]byte, error) {
|
||||||
|
b1, err := json.Marshal(p.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pths := make(map[string]PathItem)
|
||||||
|
for k, v := range p.Paths {
|
||||||
|
if strings.HasPrefix(k, "/") {
|
||||||
|
pths[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b2, err := json.Marshal(pths)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
concated := swag.ConcatJSON(b1, b2)
|
||||||
|
return concated, nil
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OrderSchemaItem holds a named schema (e.g. from a property of an object)
|
||||||
|
type OrderSchemaItem struct {
|
||||||
|
Name string
|
||||||
|
Schema
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrderSchemaItems is a sortable slice of named schemas.
|
||||||
|
// The ordering is defined by the x-order schema extension.
|
||||||
|
type OrderSchemaItems []OrderSchemaItem
|
||||||
|
|
||||||
|
// MarshalJSON produces a json object with keys defined by the name schemas
|
||||||
|
// of the OrderSchemaItems slice, keeping the original order of the slice.
|
||||||
|
func (items OrderSchemaItems) MarshalJSON() ([]byte, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
buf.WriteString("{")
|
||||||
|
for i := range items {
|
||||||
|
if i > 0 {
|
||||||
|
buf.WriteString(",")
|
||||||
|
}
|
||||||
|
buf.WriteString("\"")
|
||||||
|
buf.WriteString(items[i].Name)
|
||||||
|
buf.WriteString("\":")
|
||||||
|
bs, err := json.Marshal(&items[i].Schema)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
buf.Write(bs)
|
||||||
|
}
|
||||||
|
buf.WriteString("}")
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (items OrderSchemaItems) Len() int { return len(items) }
|
||||||
|
func (items OrderSchemaItems) Swap(i, j int) { items[i], items[j] = items[j], items[i] }
|
||||||
|
func (items OrderSchemaItems) Less(i, j int) (ret bool) {
|
||||||
|
ii, oki := items[i].Extensions.GetInt("x-order")
|
||||||
|
ij, okj := items[j].Extensions.GetInt("x-order")
|
||||||
|
if oki {
|
||||||
|
if okj {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
defer func() {
|
||||||
|
if err = recover(); err != nil {
|
||||||
|
ret = items[i].Name < items[j].Name
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
ret = reflect.ValueOf(ii).String() < reflect.ValueOf(ij).String()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return ii < ij
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} else if okj {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return items[i].Name < items[j].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// SchemaProperties is a map representing the properties of a Schema object.
|
||||||
|
// It knows how to transform its keys into an ordered slice.
|
||||||
|
type SchemaProperties map[string]Schema
|
||||||
|
|
||||||
|
// ToOrderedSchemaItems transforms the map of properties into a sortable slice
|
||||||
|
func (properties SchemaProperties) ToOrderedSchemaItems() OrderSchemaItems {
|
||||||
|
items := make(OrderSchemaItems, 0, len(properties))
|
||||||
|
for k, v := range properties {
|
||||||
|
items = append(items, OrderSchemaItem{
|
||||||
|
Name: k,
|
||||||
|
Schema: v,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
sort.Sort(items)
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON produces properties as json, keeping their order.
|
||||||
|
func (properties SchemaProperties) MarshalJSON() ([]byte, error) {
|
||||||
|
if properties == nil {
|
||||||
|
return []byte("null"), nil
|
||||||
|
}
|
||||||
|
return json.Marshal(properties.ToOrderedSchemaItems())
|
||||||
|
}
|
|
@ -0,0 +1,193 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/go-openapi/jsonreference"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Refable is a struct for things that accept a $ref property
|
||||||
|
type Refable struct {
|
||||||
|
Ref Ref
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshals the ref to json
|
||||||
|
func (r Refable) MarshalJSON() ([]byte, error) {
|
||||||
|
return r.Ref.MarshalJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshalss the ref from json
|
||||||
|
func (r *Refable) UnmarshalJSON(d []byte) error {
|
||||||
|
return json.Unmarshal(d, &r.Ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref represents a json reference that is potentially resolved
|
||||||
|
type Ref struct {
|
||||||
|
jsonreference.Ref
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteURI gets the remote uri part of the ref
|
||||||
|
func (r *Ref) RemoteURI() string {
|
||||||
|
if r.String() == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
u := *r.GetURL()
|
||||||
|
u.Fragment = ""
|
||||||
|
return u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValidURI returns true when the url the ref points to can be found
|
||||||
|
func (r *Ref) IsValidURI(basepaths ...string) bool {
|
||||||
|
if r.String() == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
v := r.RemoteURI()
|
||||||
|
if v == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.HasFullURL {
|
||||||
|
//nolint:noctx,gosec
|
||||||
|
rr, err := http.Get(v)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer rr.Body.Close()
|
||||||
|
|
||||||
|
return rr.StatusCode/100 == 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(r.HasFileScheme || r.HasFullFilePath || r.HasURLPathOnly) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for local file
|
||||||
|
pth := v
|
||||||
|
if r.HasURLPathOnly {
|
||||||
|
base := "."
|
||||||
|
if len(basepaths) > 0 {
|
||||||
|
base = filepath.Dir(filepath.Join(basepaths...))
|
||||||
|
}
|
||||||
|
p, e := filepath.Abs(filepath.ToSlash(filepath.Join(base, pth)))
|
||||||
|
if e != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
pth = p
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := os.Stat(filepath.ToSlash(pth))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return !fi.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherits creates a new reference from a parent and a child
|
||||||
|
// If the child cannot inherit from the parent, an error is returned
|
||||||
|
func (r *Ref) Inherits(child Ref) (*Ref, error) {
|
||||||
|
ref, err := r.Ref.Inherits(child.Ref)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Ref{Ref: *ref}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRef creates a new instance of a ref object
|
||||||
|
// returns an error when the reference uri is an invalid uri
|
||||||
|
func NewRef(refURI string) (Ref, error) {
|
||||||
|
ref, err := jsonreference.New(refURI)
|
||||||
|
if err != nil {
|
||||||
|
return Ref{}, err
|
||||||
|
}
|
||||||
|
return Ref{Ref: ref}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustCreateRef creates a ref object but panics when refURI is invalid.
|
||||||
|
// Use the NewRef method for a version that returns an error.
|
||||||
|
func MustCreateRef(refURI string) Ref {
|
||||||
|
return Ref{Ref: jsonreference.MustCreateRef(refURI)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshals this ref into a JSON object
|
||||||
|
func (r Ref) MarshalJSON() ([]byte, error) {
|
||||||
|
str := r.String()
|
||||||
|
if str == "" {
|
||||||
|
if r.IsRoot() {
|
||||||
|
return []byte(`{"$ref":""}`), nil
|
||||||
|
}
|
||||||
|
return []byte("{}"), nil
|
||||||
|
}
|
||||||
|
v := map[string]interface{}{"$ref": str}
|
||||||
|
return json.Marshal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals this ref from a JSON object
|
||||||
|
func (r *Ref) UnmarshalJSON(d []byte) error {
|
||||||
|
var v map[string]interface{}
|
||||||
|
if err := json.Unmarshal(d, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return r.fromMap(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GobEncode provides a safe gob encoder for Ref
|
||||||
|
func (r Ref) GobEncode() ([]byte, error) {
|
||||||
|
var b bytes.Buffer
|
||||||
|
raw, err := r.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = gob.NewEncoder(&b).Encode(raw)
|
||||||
|
return b.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GobDecode provides a safe gob decoder for Ref
|
||||||
|
func (r *Ref) GobDecode(b []byte) error {
|
||||||
|
var raw []byte
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
err := gob.NewDecoder(buf).Decode(&raw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(raw, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Ref) fromMap(v map[string]interface{}) error {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if vv, ok := v["$ref"]; ok {
|
||||||
|
if str, ok := vv.(string); ok {
|
||||||
|
ref, err := jsonreference.New(str)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*r = Ref{Ref: ref}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resolveAnyWithBase(root interface{}, ref *Ref, result interface{}, options *ExpandOptions) error {
|
||||||
|
options = optionsOrDefault(options)
|
||||||
|
resolver := defaultSchemaLoader(root, options, nil, nil)
|
||||||
|
|
||||||
|
if err := resolver.Resolve(ref, result, options.RelativeBase); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveRefWithBase resolves a reference against a context root with preservation of base path
|
||||||
|
func ResolveRefWithBase(root interface{}, ref *Ref, options *ExpandOptions) (*Schema, error) {
|
||||||
|
result := new(Schema)
|
||||||
|
|
||||||
|
if err := resolveAnyWithBase(root, ref, result, options); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveRef resolves a reference for a schema against a context root
|
||||||
|
// ref is guaranteed to be in root (no need to go to external files)
|
||||||
|
//
|
||||||
|
// ResolveRef is ONLY called from the code generation module
|
||||||
|
func ResolveRef(root interface{}, ref *Ref) (*Schema, error) {
|
||||||
|
res, _, err := ref.GetPointer().Get(root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sch := res.(type) {
|
||||||
|
case Schema:
|
||||||
|
return &sch, nil
|
||||||
|
case *Schema:
|
||||||
|
return sch, nil
|
||||||
|
case map[string]interface{}:
|
||||||
|
newSch := new(Schema)
|
||||||
|
if err = swag.DynamicJSONToStruct(sch, newSch); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newSch, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("type: %T: %w", sch, ErrUnknownTypeForReference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveParameterWithBase resolves a parameter reference against a context root and base path
|
||||||
|
func ResolveParameterWithBase(root interface{}, ref Ref, options *ExpandOptions) (*Parameter, error) {
|
||||||
|
result := new(Parameter)
|
||||||
|
|
||||||
|
if err := resolveAnyWithBase(root, &ref, result, options); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveParameter resolves a parameter reference against a context root
|
||||||
|
func ResolveParameter(root interface{}, ref Ref) (*Parameter, error) {
|
||||||
|
return ResolveParameterWithBase(root, ref, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveResponseWithBase resolves response a reference against a context root and base path
|
||||||
|
func ResolveResponseWithBase(root interface{}, ref Ref, options *ExpandOptions) (*Response, error) {
|
||||||
|
result := new(Response)
|
||||||
|
|
||||||
|
err := resolveAnyWithBase(root, &ref, result, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveResponse resolves response a reference against a context root
|
||||||
|
func ResolveResponse(root interface{}, ref Ref) (*Response, error) {
|
||||||
|
return ResolveResponseWithBase(root, ref, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolvePathItemWithBase resolves response a path item against a context root and base path
|
||||||
|
func ResolvePathItemWithBase(root interface{}, ref Ref, options *ExpandOptions) (*PathItem, error) {
|
||||||
|
result := new(PathItem)
|
||||||
|
|
||||||
|
if err := resolveAnyWithBase(root, &ref, result, options); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolvePathItem resolves response a path item against a context root and base path
|
||||||
|
//
|
||||||
|
// Deprecated: use ResolvePathItemWithBase instead
|
||||||
|
func ResolvePathItem(root interface{}, ref Ref, options *ExpandOptions) (*PathItem, error) {
|
||||||
|
return ResolvePathItemWithBase(root, ref, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveItemsWithBase resolves parameter items reference against a context root and base path.
|
||||||
|
//
|
||||||
|
// NOTE: stricly speaking, this construct is not supported by Swagger 2.0.
|
||||||
|
// Similarly, $ref are forbidden in response headers.
|
||||||
|
func ResolveItemsWithBase(root interface{}, ref Ref, options *ExpandOptions) (*Items, error) {
|
||||||
|
result := new(Items)
|
||||||
|
|
||||||
|
if err := resolveAnyWithBase(root, &ref, result, options); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveItems resolves parameter items reference against a context root and base path.
|
||||||
|
//
|
||||||
|
// Deprecated: use ResolveItemsWithBase instead
|
||||||
|
func ResolveItems(root interface{}, ref Ref, options *ExpandOptions) (*Items, error) {
|
||||||
|
return ResolveItemsWithBase(root, ref, options)
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/go-openapi/jsonpointer"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResponseProps properties specific to a response
|
||||||
|
type ResponseProps struct {
|
||||||
|
Description string `json:"description"`
|
||||||
|
Schema *Schema `json:"schema,omitempty"`
|
||||||
|
Headers map[string]Header `json:"headers,omitempty"`
|
||||||
|
Examples map[string]interface{} `json:"examples,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response describes a single response from an API Operation.
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#responseObject
|
||||||
|
type Response struct {
|
||||||
|
Refable
|
||||||
|
ResponseProps
|
||||||
|
VendorExtensible
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONLookup look up a value by the json property name
|
||||||
|
func (r Response) JSONLookup(token string) (interface{}, error) {
|
||||||
|
if ex, ok := r.Extensions[token]; ok {
|
||||||
|
return &ex, nil
|
||||||
|
}
|
||||||
|
if token == "$ref" {
|
||||||
|
return &r.Ref, nil
|
||||||
|
}
|
||||||
|
ptr, _, err := jsonpointer.GetForToken(r.ResponseProps, token)
|
||||||
|
return ptr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||||
|
func (r *Response) UnmarshalJSON(data []byte) error {
|
||||||
|
if err := json.Unmarshal(data, &r.ResponseProps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &r.Refable); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, &r.VendorExtensible)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON converts this items object to JSON
|
||||||
|
func (r Response) MarshalJSON() ([]byte, error) {
|
||||||
|
var (
|
||||||
|
b1 []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if r.Ref.String() == "" {
|
||||||
|
// when there is no $ref, empty description is rendered as an empty string
|
||||||
|
b1, err = json.Marshal(r.ResponseProps)
|
||||||
|
} else {
|
||||||
|
// when there is $ref inside the schema, description should be omitempty-ied
|
||||||
|
b1, err = json.Marshal(struct {
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Schema *Schema `json:"schema,omitempty"`
|
||||||
|
Headers map[string]Header `json:"headers,omitempty"`
|
||||||
|
Examples map[string]interface{} `json:"examples,omitempty"`
|
||||||
|
}{
|
||||||
|
Description: r.ResponseProps.Description,
|
||||||
|
Schema: r.ResponseProps.Schema,
|
||||||
|
Examples: r.ResponseProps.Examples,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b2, err := json.Marshal(r.Refable)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b3, err := json.Marshal(r.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return swag.ConcatJSON(b1, b2, b3), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewResponse creates a new response instance
|
||||||
|
func NewResponse() *Response {
|
||||||
|
return new(Response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponseRef creates a response as a json reference
|
||||||
|
func ResponseRef(url string) *Response {
|
||||||
|
resp := NewResponse()
|
||||||
|
resp.Ref = MustCreateRef(url)
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDescription sets the description on this response, allows for chaining
|
||||||
|
func (r *Response) WithDescription(description string) *Response {
|
||||||
|
r.Description = description
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSchema sets the schema on this response, allows for chaining.
|
||||||
|
// Passing a nil argument removes the schema from this response
|
||||||
|
func (r *Response) WithSchema(schema *Schema) *Response {
|
||||||
|
r.Schema = schema
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHeader adds a header to this response
|
||||||
|
func (r *Response) AddHeader(name string, header *Header) *Response {
|
||||||
|
if header == nil {
|
||||||
|
return r.RemoveHeader(name)
|
||||||
|
}
|
||||||
|
if r.Headers == nil {
|
||||||
|
r.Headers = make(map[string]Header)
|
||||||
|
}
|
||||||
|
r.Headers[name] = *header
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveHeader removes a header from this response
|
||||||
|
func (r *Response) RemoveHeader(name string) *Response {
|
||||||
|
delete(r.Headers, name)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddExample adds an example to this response
|
||||||
|
func (r *Response) AddExample(mediaType string, example interface{}) *Response {
|
||||||
|
if r.Examples == nil {
|
||||||
|
r.Examples = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
r.Examples[mediaType] = example
|
||||||
|
return r
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Responses is a container for the expected responses of an operation.
|
||||||
|
// The container maps a HTTP response code to the expected response.
|
||||||
|
// It is not expected from the documentation to necessarily cover all possible HTTP response codes,
|
||||||
|
// since they may not be known in advance. However, it is expected from the documentation to cover
|
||||||
|
// a successful operation response and any known errors.
|
||||||
|
//
|
||||||
|
// The `default` can be used a default response object for all HTTP codes that are not covered
|
||||||
|
// individually by the specification.
|
||||||
|
//
|
||||||
|
// The `Responses Object` MUST contain at least one response code, and it SHOULD be the response
|
||||||
|
// for a successful operation call.
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#responsesObject
|
||||||
|
type Responses struct {
|
||||||
|
VendorExtensible
|
||||||
|
ResponsesProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONLookup implements an interface to customize json pointer lookup
|
||||||
|
func (r Responses) JSONLookup(token string) (interface{}, error) {
|
||||||
|
if token == "default" {
|
||||||
|
return r.Default, nil
|
||||||
|
}
|
||||||
|
if ex, ok := r.Extensions[token]; ok {
|
||||||
|
return &ex, nil
|
||||||
|
}
|
||||||
|
if i, err := strconv.Atoi(token); err == nil {
|
||||||
|
if scr, ok := r.StatusCodeResponses[i]; ok {
|
||||||
|
return scr, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("object has no field %q", token)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||||
|
func (r *Responses) UnmarshalJSON(data []byte) error {
|
||||||
|
if err := json.Unmarshal(data, &r.ResponsesProps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if reflect.DeepEqual(ResponsesProps{}, r.ResponsesProps) {
|
||||||
|
r.ResponsesProps = ResponsesProps{}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON converts this items object to JSON
|
||||||
|
func (r Responses) MarshalJSON() ([]byte, error) {
|
||||||
|
b1, err := json.Marshal(r.ResponsesProps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b2, err := json.Marshal(r.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
concated := swag.ConcatJSON(b1, b2)
|
||||||
|
return concated, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponsesProps describes all responses for an operation.
|
||||||
|
// It tells what is the default response and maps all responses with a
|
||||||
|
// HTTP status code.
|
||||||
|
type ResponsesProps struct {
|
||||||
|
Default *Response
|
||||||
|
StatusCodeResponses map[int]Response
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshals responses as JSON
|
||||||
|
func (r ResponsesProps) MarshalJSON() ([]byte, error) {
|
||||||
|
toser := map[string]Response{}
|
||||||
|
if r.Default != nil {
|
||||||
|
toser["default"] = *r.Default
|
||||||
|
}
|
||||||
|
for k, v := range r.StatusCodeResponses {
|
||||||
|
toser[strconv.Itoa(k)] = v
|
||||||
|
}
|
||||||
|
return json.Marshal(toser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals responses from JSON
|
||||||
|
func (r *ResponsesProps) UnmarshalJSON(data []byte) error {
|
||||||
|
var res map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := res["default"]; ok {
|
||||||
|
var defaultRes Response
|
||||||
|
if err := json.Unmarshal(v, &defaultRes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Default = &defaultRes
|
||||||
|
delete(res, "default")
|
||||||
|
}
|
||||||
|
for k, v := range res {
|
||||||
|
if !strings.HasPrefix(k, "x-") {
|
||||||
|
var statusCodeResp Response
|
||||||
|
if err := json.Unmarshal(v, &statusCodeResp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if nk, err := strconv.Atoi(k); err == nil {
|
||||||
|
if r.StatusCodeResponses == nil {
|
||||||
|
r.StatusCodeResponses = map[int]Response{}
|
||||||
|
}
|
||||||
|
r.StatusCodeResponses[nk] = statusCodeResp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,645 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-openapi/jsonpointer"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BooleanProperty creates a boolean property
|
||||||
|
func BooleanProperty() *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"boolean"}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolProperty creates a boolean property
|
||||||
|
func BoolProperty() *Schema { return BooleanProperty() }
|
||||||
|
|
||||||
|
// StringProperty creates a string property
|
||||||
|
func StringProperty() *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CharProperty creates a string property
|
||||||
|
func CharProperty() *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Property creates a float64/double property
|
||||||
|
func Float64Property() *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "double"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32Property creates a float32/float property
|
||||||
|
func Float32Property() *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "float"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int8Property creates an int8 property
|
||||||
|
func Int8Property() *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int8"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16Property creates an int16 property
|
||||||
|
func Int16Property() *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int16"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32Property creates an int32 property
|
||||||
|
func Int32Property() *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int32"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Property creates an int64 property
|
||||||
|
func Int64Property() *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrFmtProperty creates a property for the named string format
|
||||||
|
func StrFmtProperty(format string) *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: format}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DateProperty creates a date property
|
||||||
|
func DateProperty() *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DateTimeProperty creates a date time property
|
||||||
|
func DateTimeProperty() *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date-time"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapProperty creates a map property
|
||||||
|
func MapProperty(property *Schema) *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"object"},
|
||||||
|
AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefProperty creates a ref property
|
||||||
|
func RefProperty(name string) *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefSchema creates a ref property
|
||||||
|
func RefSchema(name string) *Schema {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArrayProperty creates an array property
|
||||||
|
func ArrayProperty(items *Schema) *Schema {
|
||||||
|
if items == nil {
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Type: []string{"array"}}}
|
||||||
|
}
|
||||||
|
return &Schema{SchemaProps: SchemaProps{Items: &SchemaOrArray{Schema: items}, Type: []string{"array"}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComposedSchema creates a schema with allOf
|
||||||
|
func ComposedSchema(schemas ...Schema) *Schema {
|
||||||
|
s := new(Schema)
|
||||||
|
s.AllOf = schemas
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// SchemaURL represents a schema url
|
||||||
|
type SchemaURL string
|
||||||
|
|
||||||
|
// MarshalJSON marshal this to JSON
|
||||||
|
func (r SchemaURL) MarshalJSON() ([]byte, error) {
|
||||||
|
if r == "" {
|
||||||
|
return []byte("{}"), nil
|
||||||
|
}
|
||||||
|
v := map[string]interface{}{"$schema": string(r)}
|
||||||
|
return json.Marshal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshal this from JSON
|
||||||
|
func (r *SchemaURL) UnmarshalJSON(data []byte) error {
|
||||||
|
var v map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return r.fromMap(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SchemaURL) fromMap(v map[string]interface{}) error {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if vv, ok := v["$schema"]; ok {
|
||||||
|
if str, ok := vv.(string); ok {
|
||||||
|
u, err := parseURL(str)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*r = SchemaURL(u.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SchemaProps describes a JSON schema (draft 4)
|
||||||
|
type SchemaProps struct {
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Ref Ref `json:"-"`
|
||||||
|
Schema SchemaURL `json:"-"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Type StringOrArray `json:"type,omitempty"`
|
||||||
|
Nullable bool `json:"nullable,omitempty"`
|
||||||
|
Format string `json:"format,omitempty"`
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
Default interface{} `json:"default,omitempty"`
|
||||||
|
Maximum *float64 `json:"maximum,omitempty"`
|
||||||
|
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
|
||||||
|
Minimum *float64 `json:"minimum,omitempty"`
|
||||||
|
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"`
|
||||||
|
MaxLength *int64 `json:"maxLength,omitempty"`
|
||||||
|
MinLength *int64 `json:"minLength,omitempty"`
|
||||||
|
Pattern string `json:"pattern,omitempty"`
|
||||||
|
MaxItems *int64 `json:"maxItems,omitempty"`
|
||||||
|
MinItems *int64 `json:"minItems,omitempty"`
|
||||||
|
UniqueItems bool `json:"uniqueItems,omitempty"`
|
||||||
|
MultipleOf *float64 `json:"multipleOf,omitempty"`
|
||||||
|
Enum []interface{} `json:"enum,omitempty"`
|
||||||
|
MaxProperties *int64 `json:"maxProperties,omitempty"`
|
||||||
|
MinProperties *int64 `json:"minProperties,omitempty"`
|
||||||
|
Required []string `json:"required,omitempty"`
|
||||||
|
Items *SchemaOrArray `json:"items,omitempty"`
|
||||||
|
AllOf []Schema `json:"allOf,omitempty"`
|
||||||
|
OneOf []Schema `json:"oneOf,omitempty"`
|
||||||
|
AnyOf []Schema `json:"anyOf,omitempty"`
|
||||||
|
Not *Schema `json:"not,omitempty"`
|
||||||
|
Properties SchemaProperties `json:"properties,omitempty"`
|
||||||
|
AdditionalProperties *SchemaOrBool `json:"additionalProperties,omitempty"`
|
||||||
|
PatternProperties SchemaProperties `json:"patternProperties,omitempty"`
|
||||||
|
Dependencies Dependencies `json:"dependencies,omitempty"`
|
||||||
|
AdditionalItems *SchemaOrBool `json:"additionalItems,omitempty"`
|
||||||
|
Definitions Definitions `json:"definitions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SwaggerSchemaProps are additional properties supported by swagger schemas, but not JSON-schema (draft 4)
|
||||||
|
type SwaggerSchemaProps struct {
|
||||||
|
Discriminator string `json:"discriminator,omitempty"`
|
||||||
|
ReadOnly bool `json:"readOnly,omitempty"`
|
||||||
|
XML *XMLObject `json:"xml,omitempty"`
|
||||||
|
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||||
|
Example interface{} `json:"example,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schema the schema object allows the definition of input and output data types.
|
||||||
|
// These types can be objects, but also primitives and arrays.
|
||||||
|
// This object is based on the [JSON Schema Specification Draft 4](http://json-schema.org/)
|
||||||
|
// and uses a predefined subset of it.
|
||||||
|
// On top of this subset, there are extensions provided by this specification to allow for more complete documentation.
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#schemaObject
|
||||||
|
type Schema struct {
|
||||||
|
VendorExtensible
|
||||||
|
SchemaProps
|
||||||
|
SwaggerSchemaProps
|
||||||
|
ExtraProps map[string]interface{} `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONLookup implements an interface to customize json pointer lookup
|
||||||
|
func (s Schema) JSONLookup(token string) (interface{}, error) {
|
||||||
|
if ex, ok := s.Extensions[token]; ok {
|
||||||
|
return &ex, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ex, ok := s.ExtraProps[token]; ok {
|
||||||
|
return &ex, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r, _, err := jsonpointer.GetForToken(s.SchemaProps, token)
|
||||||
|
if r != nil || (err != nil && !strings.HasPrefix(err.Error(), "object has no field")) {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
r, _, err = jsonpointer.GetForToken(s.SwaggerSchemaProps, token)
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithID sets the id for this schema, allows for chaining
|
||||||
|
func (s *Schema) WithID(id string) *Schema {
|
||||||
|
s.ID = id
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTitle sets the title for this schema, allows for chaining
|
||||||
|
func (s *Schema) WithTitle(title string) *Schema {
|
||||||
|
s.Title = title
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDescription sets the description for this schema, allows for chaining
|
||||||
|
func (s *Schema) WithDescription(description string) *Schema {
|
||||||
|
s.Description = description
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithProperties sets the properties for this schema
|
||||||
|
func (s *Schema) WithProperties(schemas map[string]Schema) *Schema {
|
||||||
|
s.Properties = schemas
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProperty sets a property on this schema
|
||||||
|
func (s *Schema) SetProperty(name string, schema Schema) *Schema {
|
||||||
|
if s.Properties == nil {
|
||||||
|
s.Properties = make(map[string]Schema)
|
||||||
|
}
|
||||||
|
s.Properties[name] = schema
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAllOf sets the all of property
|
||||||
|
func (s *Schema) WithAllOf(schemas ...Schema) *Schema {
|
||||||
|
s.AllOf = schemas
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxProperties sets the max number of properties an object can have
|
||||||
|
func (s *Schema) WithMaxProperties(max int64) *Schema {
|
||||||
|
s.MaxProperties = &max
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinProperties sets the min number of properties an object must have
|
||||||
|
func (s *Schema) WithMinProperties(min int64) *Schema {
|
||||||
|
s.MinProperties = &min
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typed sets the type of this schema for a single value item
|
||||||
|
func (s *Schema) Typed(tpe, format string) *Schema {
|
||||||
|
s.Type = []string{tpe}
|
||||||
|
s.Format = format
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddType adds a type with potential format to the types for this schema
|
||||||
|
func (s *Schema) AddType(tpe, format string) *Schema {
|
||||||
|
s.Type = append(s.Type, tpe)
|
||||||
|
if format != "" {
|
||||||
|
s.Format = format
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsNullable flags this schema as nullable.
|
||||||
|
func (s *Schema) AsNullable() *Schema {
|
||||||
|
s.Nullable = true
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// CollectionOf a fluent builder method for an array parameter
|
||||||
|
func (s *Schema) CollectionOf(items Schema) *Schema {
|
||||||
|
s.Type = []string{jsonArray}
|
||||||
|
s.Items = &SchemaOrArray{Schema: &items}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDefault sets the default value on this parameter
|
||||||
|
func (s *Schema) WithDefault(defaultValue interface{}) *Schema {
|
||||||
|
s.Default = defaultValue
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRequired flags this parameter as required
|
||||||
|
func (s *Schema) WithRequired(items ...string) *Schema {
|
||||||
|
s.Required = items
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRequired adds field names to the required properties array
|
||||||
|
func (s *Schema) AddRequired(items ...string) *Schema {
|
||||||
|
s.Required = append(s.Required, items...)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxLength sets a max length value
|
||||||
|
func (s *Schema) WithMaxLength(max int64) *Schema {
|
||||||
|
s.MaxLength = &max
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinLength sets a min length value
|
||||||
|
func (s *Schema) WithMinLength(min int64) *Schema {
|
||||||
|
s.MinLength = &min
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPattern sets a pattern value
|
||||||
|
func (s *Schema) WithPattern(pattern string) *Schema {
|
||||||
|
s.Pattern = pattern
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMultipleOf sets a multiple of value
|
||||||
|
func (s *Schema) WithMultipleOf(number float64) *Schema {
|
||||||
|
s.MultipleOf = &number
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaximum sets a maximum number value
|
||||||
|
func (s *Schema) WithMaximum(max float64, exclusive bool) *Schema {
|
||||||
|
s.Maximum = &max
|
||||||
|
s.ExclusiveMaximum = exclusive
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinimum sets a minimum number value
|
||||||
|
func (s *Schema) WithMinimum(min float64, exclusive bool) *Schema {
|
||||||
|
s.Minimum = &min
|
||||||
|
s.ExclusiveMinimum = exclusive
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEnum sets a the enum values (replace)
|
||||||
|
func (s *Schema) WithEnum(values ...interface{}) *Schema {
|
||||||
|
s.Enum = append([]interface{}{}, values...)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxItems sets the max items
|
||||||
|
func (s *Schema) WithMaxItems(size int64) *Schema {
|
||||||
|
s.MaxItems = &size
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMinItems sets the min items
|
||||||
|
func (s *Schema) WithMinItems(size int64) *Schema {
|
||||||
|
s.MinItems = &size
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// UniqueValues dictates that this array can only have unique items
|
||||||
|
func (s *Schema) UniqueValues() *Schema {
|
||||||
|
s.UniqueItems = true
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowDuplicates this array can have duplicates
|
||||||
|
func (s *Schema) AllowDuplicates() *Schema {
|
||||||
|
s.UniqueItems = false
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddToAllOf adds a schema to the allOf property
|
||||||
|
func (s *Schema) AddToAllOf(schemas ...Schema) *Schema {
|
||||||
|
s.AllOf = append(s.AllOf, schemas...)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDiscriminator sets the name of the discriminator field
|
||||||
|
func (s *Schema) WithDiscriminator(discriminator string) *Schema {
|
||||||
|
s.Discriminator = discriminator
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsReadOnly flags this schema as readonly
|
||||||
|
func (s *Schema) AsReadOnly() *Schema {
|
||||||
|
s.ReadOnly = true
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsWritable flags this schema as writeable (not read-only)
|
||||||
|
func (s *Schema) AsWritable() *Schema {
|
||||||
|
s.ReadOnly = false
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithExample sets the example for this schema
|
||||||
|
func (s *Schema) WithExample(example interface{}) *Schema {
|
||||||
|
s.Example = example
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithExternalDocs sets/removes the external docs for/from this schema.
|
||||||
|
// When you pass empty strings as params the external documents will be removed.
|
||||||
|
// When you pass non-empty string as one value then those values will be used on the external docs object.
|
||||||
|
// So when you pass a non-empty description, you should also pass the url and vice versa.
|
||||||
|
func (s *Schema) WithExternalDocs(description, url string) *Schema {
|
||||||
|
if description == "" && url == "" {
|
||||||
|
s.ExternalDocs = nil
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.ExternalDocs == nil {
|
||||||
|
s.ExternalDocs = &ExternalDocumentation{}
|
||||||
|
}
|
||||||
|
s.ExternalDocs.Description = description
|
||||||
|
s.ExternalDocs.URL = url
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithXMLName sets the xml name for the object
|
||||||
|
func (s *Schema) WithXMLName(name string) *Schema {
|
||||||
|
if s.XML == nil {
|
||||||
|
s.XML = new(XMLObject)
|
||||||
|
}
|
||||||
|
s.XML.Name = name
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithXMLNamespace sets the xml namespace for the object
|
||||||
|
func (s *Schema) WithXMLNamespace(namespace string) *Schema {
|
||||||
|
if s.XML == nil {
|
||||||
|
s.XML = new(XMLObject)
|
||||||
|
}
|
||||||
|
s.XML.Namespace = namespace
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithXMLPrefix sets the xml prefix for the object
|
||||||
|
func (s *Schema) WithXMLPrefix(prefix string) *Schema {
|
||||||
|
if s.XML == nil {
|
||||||
|
s.XML = new(XMLObject)
|
||||||
|
}
|
||||||
|
s.XML.Prefix = prefix
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsXMLAttribute flags this object as xml attribute
|
||||||
|
func (s *Schema) AsXMLAttribute() *Schema {
|
||||||
|
if s.XML == nil {
|
||||||
|
s.XML = new(XMLObject)
|
||||||
|
}
|
||||||
|
s.XML.Attribute = true
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsXMLElement flags this object as an xml node
|
||||||
|
func (s *Schema) AsXMLElement() *Schema {
|
||||||
|
if s.XML == nil {
|
||||||
|
s.XML = new(XMLObject)
|
||||||
|
}
|
||||||
|
s.XML.Attribute = false
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsWrappedXML flags this object as wrapped, this is mostly useful for array types
|
||||||
|
func (s *Schema) AsWrappedXML() *Schema {
|
||||||
|
if s.XML == nil {
|
||||||
|
s.XML = new(XMLObject)
|
||||||
|
}
|
||||||
|
s.XML.Wrapped = true
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsUnwrappedXML flags this object as an xml node
|
||||||
|
func (s *Schema) AsUnwrappedXML() *Schema {
|
||||||
|
if s.XML == nil {
|
||||||
|
s.XML = new(XMLObject)
|
||||||
|
}
|
||||||
|
s.XML.Wrapped = false
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetValidations defines all schema validations.
|
||||||
|
//
|
||||||
|
// NOTE: Required, ReadOnly, AllOf, AnyOf, OneOf and Not are not considered.
|
||||||
|
func (s *Schema) SetValidations(val SchemaValidations) {
|
||||||
|
s.Maximum = val.Maximum
|
||||||
|
s.ExclusiveMaximum = val.ExclusiveMaximum
|
||||||
|
s.Minimum = val.Minimum
|
||||||
|
s.ExclusiveMinimum = val.ExclusiveMinimum
|
||||||
|
s.MaxLength = val.MaxLength
|
||||||
|
s.MinLength = val.MinLength
|
||||||
|
s.Pattern = val.Pattern
|
||||||
|
s.MaxItems = val.MaxItems
|
||||||
|
s.MinItems = val.MinItems
|
||||||
|
s.UniqueItems = val.UniqueItems
|
||||||
|
s.MultipleOf = val.MultipleOf
|
||||||
|
s.Enum = val.Enum
|
||||||
|
s.MinProperties = val.MinProperties
|
||||||
|
s.MaxProperties = val.MaxProperties
|
||||||
|
s.PatternProperties = val.PatternProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithValidations is a fluent method to set schema validations
|
||||||
|
func (s *Schema) WithValidations(val SchemaValidations) *Schema {
|
||||||
|
s.SetValidations(val)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validations returns a clone of the validations for this schema
|
||||||
|
func (s Schema) Validations() SchemaValidations {
|
||||||
|
return SchemaValidations{
|
||||||
|
CommonValidations: CommonValidations{
|
||||||
|
Maximum: s.Maximum,
|
||||||
|
ExclusiveMaximum: s.ExclusiveMaximum,
|
||||||
|
Minimum: s.Minimum,
|
||||||
|
ExclusiveMinimum: s.ExclusiveMinimum,
|
||||||
|
MaxLength: s.MaxLength,
|
||||||
|
MinLength: s.MinLength,
|
||||||
|
Pattern: s.Pattern,
|
||||||
|
MaxItems: s.MaxItems,
|
||||||
|
MinItems: s.MinItems,
|
||||||
|
UniqueItems: s.UniqueItems,
|
||||||
|
MultipleOf: s.MultipleOf,
|
||||||
|
Enum: s.Enum,
|
||||||
|
},
|
||||||
|
MinProperties: s.MinProperties,
|
||||||
|
MaxProperties: s.MaxProperties,
|
||||||
|
PatternProperties: s.PatternProperties,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshal this to JSON
|
||||||
|
func (s Schema) MarshalJSON() ([]byte, error) {
|
||||||
|
b1, err := json.Marshal(s.SchemaProps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("schema props %v", err)
|
||||||
|
}
|
||||||
|
b2, err := json.Marshal(s.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("vendor props %v", err)
|
||||||
|
}
|
||||||
|
b3, err := s.Ref.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ref prop %v", err)
|
||||||
|
}
|
||||||
|
b4, err := s.Schema.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("schema prop %v", err)
|
||||||
|
}
|
||||||
|
b5, err := json.Marshal(s.SwaggerSchemaProps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("common validations %v", err)
|
||||||
|
}
|
||||||
|
var b6 []byte
|
||||||
|
if s.ExtraProps != nil {
|
||||||
|
jj, err := json.Marshal(s.ExtraProps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("extra props %v", err)
|
||||||
|
}
|
||||||
|
b6 = jj
|
||||||
|
}
|
||||||
|
return swag.ConcatJSON(b1, b2, b3, b4, b5, b6), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON marshal this from JSON
|
||||||
|
func (s *Schema) UnmarshalJSON(data []byte) error {
|
||||||
|
props := struct {
|
||||||
|
SchemaProps
|
||||||
|
SwaggerSchemaProps
|
||||||
|
}{}
|
||||||
|
if err := json.Unmarshal(data, &props); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sch := Schema{
|
||||||
|
SchemaProps: props.SchemaProps,
|
||||||
|
SwaggerSchemaProps: props.SwaggerSchemaProps,
|
||||||
|
}
|
||||||
|
|
||||||
|
var d map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &d); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = sch.Ref.fromMap(d)
|
||||||
|
_ = sch.Schema.fromMap(d)
|
||||||
|
|
||||||
|
delete(d, "$ref")
|
||||||
|
delete(d, "$schema")
|
||||||
|
for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) {
|
||||||
|
delete(d, pn)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, vv := range d {
|
||||||
|
lk := strings.ToLower(k)
|
||||||
|
if strings.HasPrefix(lk, "x-") {
|
||||||
|
if sch.Extensions == nil {
|
||||||
|
sch.Extensions = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
sch.Extensions[k] = vv
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if sch.ExtraProps == nil {
|
||||||
|
sch.ExtraProps = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
sch.ExtraProps[k] = vv
|
||||||
|
}
|
||||||
|
|
||||||
|
*s = sch
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,331 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PathLoader is a function to use when loading remote refs.
|
||||||
|
//
|
||||||
|
// This is a package level default. It may be overridden or bypassed by
|
||||||
|
// specifying the loader in ExpandOptions.
|
||||||
|
//
|
||||||
|
// NOTE: if you are using the go-openapi/loads package, it will override
|
||||||
|
// this value with its own default (a loader to retrieve YAML documents as
|
||||||
|
// well as JSON ones).
|
||||||
|
var PathLoader = func(pth string) (json.RawMessage, error) {
|
||||||
|
data, err := swag.LoadFromFileOrHTTP(pth)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return json.RawMessage(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolverContext allows to share a context during spec processing.
|
||||||
|
// At the moment, it just holds the index of circular references found.
|
||||||
|
type resolverContext struct {
|
||||||
|
// circulars holds all visited circular references, to shortcircuit $ref resolution.
|
||||||
|
//
|
||||||
|
// This structure is privately instantiated and needs not be locked against
|
||||||
|
// concurrent access, unless we chose to implement a parallel spec walking.
|
||||||
|
circulars map[string]bool
|
||||||
|
basePath string
|
||||||
|
loadDoc func(string) (json.RawMessage, error)
|
||||||
|
rootID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newResolverContext(options *ExpandOptions) *resolverContext {
|
||||||
|
expandOptions := optionsOrDefault(options)
|
||||||
|
|
||||||
|
// path loader may be overridden by options
|
||||||
|
var loader func(string) (json.RawMessage, error)
|
||||||
|
if expandOptions.PathLoader == nil {
|
||||||
|
loader = PathLoader
|
||||||
|
} else {
|
||||||
|
loader = expandOptions.PathLoader
|
||||||
|
}
|
||||||
|
|
||||||
|
return &resolverContext{
|
||||||
|
circulars: make(map[string]bool),
|
||||||
|
basePath: expandOptions.RelativeBase, // keep the root base path in context
|
||||||
|
loadDoc: loader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type schemaLoader struct {
|
||||||
|
root interface{}
|
||||||
|
options *ExpandOptions
|
||||||
|
cache ResolutionCache
|
||||||
|
context *resolverContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *schemaLoader) transitiveResolver(basePath string, ref Ref) *schemaLoader {
|
||||||
|
if ref.IsRoot() || ref.HasFragmentOnly {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
baseRef := MustCreateRef(basePath)
|
||||||
|
currentRef := normalizeRef(&ref, basePath)
|
||||||
|
if strings.HasPrefix(currentRef.String(), baseRef.String()) {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// set a new root against which to resolve
|
||||||
|
rootURL := currentRef.GetURL()
|
||||||
|
rootURL.Fragment = ""
|
||||||
|
root, _ := r.cache.Get(rootURL.String())
|
||||||
|
|
||||||
|
// shallow copy of resolver options to set a new RelativeBase when
|
||||||
|
// traversing multiple documents
|
||||||
|
newOptions := r.options
|
||||||
|
newOptions.RelativeBase = rootURL.String()
|
||||||
|
|
||||||
|
return defaultSchemaLoader(root, newOptions, r.cache, r.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *schemaLoader) updateBasePath(transitive *schemaLoader, basePath string) string {
|
||||||
|
if transitive != r {
|
||||||
|
if transitive.options != nil && transitive.options.RelativeBase != "" {
|
||||||
|
return normalizeBase(transitive.options.RelativeBase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return basePath
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *schemaLoader) resolveRef(ref *Ref, target interface{}, basePath string) error {
|
||||||
|
tgt := reflect.ValueOf(target)
|
||||||
|
if tgt.Kind() != reflect.Ptr {
|
||||||
|
return ErrResolveRefNeedsAPointer
|
||||||
|
}
|
||||||
|
|
||||||
|
if ref.GetURL() == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
res interface{}
|
||||||
|
data interface{}
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resolve against the root if it isn't nil, and if ref is pointing at the root, or has a fragment only which means
|
||||||
|
// it is pointing somewhere in the root.
|
||||||
|
root := r.root
|
||||||
|
if (ref.IsRoot() || ref.HasFragmentOnly) && root == nil && basePath != "" {
|
||||||
|
if baseRef, erb := NewRef(basePath); erb == nil {
|
||||||
|
root, _, _, _ = r.load(baseRef.GetURL())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ref.IsRoot() || ref.HasFragmentOnly) && root != nil {
|
||||||
|
data = root
|
||||||
|
} else {
|
||||||
|
baseRef := normalizeRef(ref, basePath)
|
||||||
|
data, _, _, err = r.load(baseRef.GetURL())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = data
|
||||||
|
if ref.String() != "" {
|
||||||
|
res, _, err = ref.GetPointer().Get(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return swag.DynamicJSONToStruct(res, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error) {
|
||||||
|
debugLog("loading schema from url: %s", refURL)
|
||||||
|
toFetch := *refURL
|
||||||
|
toFetch.Fragment = ""
|
||||||
|
|
||||||
|
var err error
|
||||||
|
pth := toFetch.String()
|
||||||
|
normalized := normalizeBase(pth)
|
||||||
|
debugLog("loading doc from: %s", normalized)
|
||||||
|
|
||||||
|
data, fromCache := r.cache.Get(normalized)
|
||||||
|
if fromCache {
|
||||||
|
return data, toFetch, fromCache, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := r.context.loadDoc(normalized)
|
||||||
|
if err != nil {
|
||||||
|
return nil, url.URL{}, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var doc interface{}
|
||||||
|
if err := json.Unmarshal(b, &doc); err != nil {
|
||||||
|
return nil, url.URL{}, false, err
|
||||||
|
}
|
||||||
|
r.cache.Set(normalized, doc)
|
||||||
|
|
||||||
|
return doc, toFetch, fromCache, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isCircular detects cycles in sequences of $ref.
|
||||||
|
//
|
||||||
|
// It relies on a private context (which needs not be locked).
|
||||||
|
func (r *schemaLoader) isCircular(ref *Ref, basePath string, parentRefs ...string) (foundCycle bool) {
|
||||||
|
normalizedRef := normalizeURI(ref.String(), basePath)
|
||||||
|
if _, ok := r.context.circulars[normalizedRef]; ok {
|
||||||
|
// circular $ref has been already detected in another explored cycle
|
||||||
|
foundCycle = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
foundCycle = swag.ContainsStrings(parentRefs, normalizedRef) // normalized windows url's are lower cased
|
||||||
|
if foundCycle {
|
||||||
|
r.context.circulars[normalizedRef] = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve resolves a reference against basePath and stores the result in target.
|
||||||
|
//
|
||||||
|
// Resolve is not in charge of following references: it only resolves ref by following its URL.
|
||||||
|
//
|
||||||
|
// If the schema the ref is referring to holds nested refs, Resolve doesn't resolve them.
|
||||||
|
//
|
||||||
|
// If basePath is an empty string, ref is resolved against the root schema stored in the schemaLoader struct
|
||||||
|
func (r *schemaLoader) Resolve(ref *Ref, target interface{}, basePath string) error {
|
||||||
|
return r.resolveRef(ref, target, basePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *schemaLoader) deref(input interface{}, parentRefs []string, basePath string) error {
|
||||||
|
var ref *Ref
|
||||||
|
switch refable := input.(type) {
|
||||||
|
case *Schema:
|
||||||
|
ref = &refable.Ref
|
||||||
|
case *Parameter:
|
||||||
|
ref = &refable.Ref
|
||||||
|
case *Response:
|
||||||
|
ref = &refable.Ref
|
||||||
|
case *PathItem:
|
||||||
|
ref = &refable.Ref
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported type: %T: %w", input, ErrDerefUnsupportedType)
|
||||||
|
}
|
||||||
|
|
||||||
|
curRef := ref.String()
|
||||||
|
if curRef == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizedRef := normalizeRef(ref, basePath)
|
||||||
|
normalizedBasePath := normalizedRef.RemoteURI()
|
||||||
|
|
||||||
|
if r.isCircular(normalizedRef, basePath, parentRefs...) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.resolveRef(ref, input, basePath); r.shouldStopOnError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ref.String() == "" || ref.String() == curRef {
|
||||||
|
// done with rereferencing
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
parentRefs = append(parentRefs, normalizedRef.String())
|
||||||
|
return r.deref(input, parentRefs, normalizedBasePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *schemaLoader) shouldStopOnError(err error) bool {
|
||||||
|
if err != nil && !r.options.ContinueOnError {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *schemaLoader) setSchemaID(target interface{}, id, basePath string) (string, string) {
|
||||||
|
debugLog("schema has ID: %s", id)
|
||||||
|
|
||||||
|
// handling the case when id is a folder
|
||||||
|
// remember that basePath has to point to a file
|
||||||
|
var refPath string
|
||||||
|
if strings.HasSuffix(id, "/") {
|
||||||
|
// ensure this is detected as a file, not a folder
|
||||||
|
refPath = fmt.Sprintf("%s%s", id, "placeholder.json")
|
||||||
|
} else {
|
||||||
|
refPath = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// updates the current base path
|
||||||
|
// * important: ID can be a relative path
|
||||||
|
// * registers target to be fetchable from the new base proposed by this id
|
||||||
|
newBasePath := normalizeURI(refPath, basePath)
|
||||||
|
|
||||||
|
// store found IDs for possible future reuse in $ref
|
||||||
|
r.cache.Set(newBasePath, target)
|
||||||
|
|
||||||
|
// the root document has an ID: all $ref relative to that ID may
|
||||||
|
// be rebased relative to the root document
|
||||||
|
if basePath == r.context.basePath {
|
||||||
|
debugLog("root document is a schema with ID: %s (normalized as:%s)", id, newBasePath)
|
||||||
|
r.context.rootID = newBasePath
|
||||||
|
}
|
||||||
|
|
||||||
|
return newBasePath, refPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultSchemaLoader(
|
||||||
|
root interface{},
|
||||||
|
expandOptions *ExpandOptions,
|
||||||
|
cache ResolutionCache,
|
||||||
|
context *resolverContext) *schemaLoader {
|
||||||
|
|
||||||
|
if expandOptions == nil {
|
||||||
|
expandOptions = &ExpandOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
cache = cacheOrDefault(cache)
|
||||||
|
|
||||||
|
if expandOptions.RelativeBase == "" {
|
||||||
|
// if no relative base is provided, assume the root document
|
||||||
|
// contains all $ref, or at least, that the relative documents
|
||||||
|
// may be resolved from the current working directory.
|
||||||
|
expandOptions.RelativeBase = baseForRoot(root, cache)
|
||||||
|
}
|
||||||
|
debugLog("effective expander options: %#v", expandOptions)
|
||||||
|
|
||||||
|
if context == nil {
|
||||||
|
context = newResolverContext(expandOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &schemaLoader{
|
||||||
|
root: root,
|
||||||
|
options: expandOptions,
|
||||||
|
cache: cache,
|
||||||
|
context: context,
|
||||||
|
}
|
||||||
|
}
|
149
vendor/github.com/go-openapi/spec/schemas/jsonschema-draft-04.json
generated
vendored
Normal file
149
vendor/github.com/go-openapi/spec/schemas/jsonschema-draft-04.json
generated
vendored
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
{
|
||||||
|
"id": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"description": "Core schema meta-schema",
|
||||||
|
"definitions": {
|
||||||
|
"schemaArray": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": { "$ref": "#" }
|
||||||
|
},
|
||||||
|
"positiveInteger": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"positiveIntegerDefault0": {
|
||||||
|
"allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
|
||||||
|
},
|
||||||
|
"simpleTypes": {
|
||||||
|
"enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
|
||||||
|
},
|
||||||
|
"stringArray": {
|
||||||
|
"type": "array",
|
||||||
|
"items": { "type": "string" },
|
||||||
|
"minItems": 1,
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"$schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"default": {},
|
||||||
|
"multipleOf": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"exclusiveMinimum": true
|
||||||
|
},
|
||||||
|
"maximum": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"exclusiveMaximum": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"minimum": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"exclusiveMinimum": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"maxLength": { "$ref": "#/definitions/positiveInteger" },
|
||||||
|
"minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
|
||||||
|
"pattern": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "regex"
|
||||||
|
},
|
||||||
|
"additionalItems": {
|
||||||
|
"anyOf": [
|
||||||
|
{ "type": "boolean" },
|
||||||
|
{ "$ref": "#" }
|
||||||
|
],
|
||||||
|
"default": {}
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"anyOf": [
|
||||||
|
{ "$ref": "#" },
|
||||||
|
{ "$ref": "#/definitions/schemaArray" }
|
||||||
|
],
|
||||||
|
"default": {}
|
||||||
|
},
|
||||||
|
"maxItems": { "$ref": "#/definitions/positiveInteger" },
|
||||||
|
"minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
|
||||||
|
"uniqueItems": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"maxProperties": { "$ref": "#/definitions/positiveInteger" },
|
||||||
|
"minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
|
||||||
|
"required": { "$ref": "#/definitions/stringArray" },
|
||||||
|
"additionalProperties": {
|
||||||
|
"anyOf": [
|
||||||
|
{ "type": "boolean" },
|
||||||
|
{ "$ref": "#" }
|
||||||
|
],
|
||||||
|
"default": {}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": { "$ref": "#" },
|
||||||
|
"default": {}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": { "$ref": "#" },
|
||||||
|
"default": {}
|
||||||
|
},
|
||||||
|
"patternProperties": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": { "$ref": "#" },
|
||||||
|
"default": {}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"anyOf": [
|
||||||
|
{ "$ref": "#" },
|
||||||
|
{ "$ref": "#/definitions/stringArray" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enum": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"anyOf": [
|
||||||
|
{ "$ref": "#/definitions/simpleTypes" },
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": { "$ref": "#/definitions/simpleTypes" },
|
||||||
|
"minItems": 1,
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"format": { "type": "string" },
|
||||||
|
"allOf": { "$ref": "#/definitions/schemaArray" },
|
||||||
|
"anyOf": { "$ref": "#/definitions/schemaArray" },
|
||||||
|
"oneOf": { "$ref": "#/definitions/schemaArray" },
|
||||||
|
"not": { "$ref": "#" }
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"exclusiveMaximum": [ "maximum" ],
|
||||||
|
"exclusiveMinimum": [ "minimum" ]
|
||||||
|
},
|
||||||
|
"default": {}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,170 @@
|
||||||
|
// Copyright 2015 go-swagger maintainers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/go-openapi/jsonpointer"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
basic = "basic"
|
||||||
|
apiKey = "apiKey"
|
||||||
|
oauth2 = "oauth2"
|
||||||
|
implicit = "implicit"
|
||||||
|
password = "password"
|
||||||
|
application = "application"
|
||||||
|
accessCode = "accessCode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BasicAuth creates a basic auth security scheme
|
||||||
|
func BasicAuth() *SecurityScheme {
|
||||||
|
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: basic}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIKeyAuth creates an api key auth security scheme
|
||||||
|
func APIKeyAuth(fieldName, valueSource string) *SecurityScheme {
|
||||||
|
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: apiKey, Name: fieldName, In: valueSource}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OAuth2Implicit creates an implicit flow oauth2 security scheme
|
||||||
|
func OAuth2Implicit(authorizationURL string) *SecurityScheme {
|
||||||
|
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{
|
||||||
|
Type: oauth2,
|
||||||
|
Flow: implicit,
|
||||||
|
AuthorizationURL: authorizationURL,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OAuth2Password creates a password flow oauth2 security scheme
|
||||||
|
func OAuth2Password(tokenURL string) *SecurityScheme {
|
||||||
|
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{
|
||||||
|
Type: oauth2,
|
||||||
|
Flow: password,
|
||||||
|
TokenURL: tokenURL,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OAuth2Application creates an application flow oauth2 security scheme
|
||||||
|
func OAuth2Application(tokenURL string) *SecurityScheme {
|
||||||
|
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{
|
||||||
|
Type: oauth2,
|
||||||
|
Flow: application,
|
||||||
|
TokenURL: tokenURL,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OAuth2AccessToken creates an access token flow oauth2 security scheme
|
||||||
|
func OAuth2AccessToken(authorizationURL, tokenURL string) *SecurityScheme {
|
||||||
|
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{
|
||||||
|
Type: oauth2,
|
||||||
|
Flow: accessCode,
|
||||||
|
AuthorizationURL: authorizationURL,
|
||||||
|
TokenURL: tokenURL,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecuritySchemeProps describes a swagger security scheme in the securityDefinitions section
|
||||||
|
type SecuritySchemeProps struct {
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Name string `json:"name,omitempty"` // api key
|
||||||
|
In string `json:"in,omitempty"` // api key
|
||||||
|
Flow string `json:"flow,omitempty"` // oauth2
|
||||||
|
AuthorizationURL string `json:"authorizationUrl"` // oauth2
|
||||||
|
TokenURL string `json:"tokenUrl,omitempty"` // oauth2
|
||||||
|
Scopes map[string]string `json:"scopes,omitempty"` // oauth2
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddScope adds a scope to this security scheme
|
||||||
|
func (s *SecuritySchemeProps) AddScope(scope, description string) {
|
||||||
|
if s.Scopes == nil {
|
||||||
|
s.Scopes = make(map[string]string)
|
||||||
|
}
|
||||||
|
s.Scopes[scope] = description
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecurityScheme allows the definition of a security scheme that can be used by the operations.
|
||||||
|
// Supported schemes are basic authentication, an API key (either as a header or as a query parameter)
|
||||||
|
// and OAuth2's common flows (implicit, password, application and access code).
|
||||||
|
//
|
||||||
|
// For more information: http://goo.gl/8us55a#securitySchemeObject
|
||||||
|
type SecurityScheme struct {
|
||||||
|
VendorExtensible
|
||||||
|
SecuritySchemeProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONLookup implements an interface to customize json pointer lookup
|
||||||
|
func (s SecurityScheme) JSONLookup(token string) (interface{}, error) {
|
||||||
|
if ex, ok := s.Extensions[token]; ok {
|
||||||
|
return &ex, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r, _, err := jsonpointer.GetForToken(s.SecuritySchemeProps, token)
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshal this to JSON
|
||||||
|
func (s SecurityScheme) MarshalJSON() ([]byte, error) {
|
||||||
|
var (
|
||||||
|
b1 []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if s.Type == oauth2 && (s.Flow == "implicit" || s.Flow == "accessCode") {
|
||||||
|
// when oauth2 for implicit or accessCode flows, empty AuthorizationURL is added as empty string
|
||||||
|
b1, err = json.Marshal(s.SecuritySchemeProps)
|
||||||
|
} else {
|
||||||
|
// when not oauth2, empty AuthorizationURL should be omitted
|
||||||
|
b1, err = json.Marshal(struct {
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Name string `json:"name,omitempty"` // api key
|
||||||
|
In string `json:"in,omitempty"` // api key
|
||||||
|
Flow string `json:"flow,omitempty"` // oauth2
|
||||||
|
AuthorizationURL string `json:"authorizationUrl,omitempty"` // oauth2
|
||||||
|
TokenURL string `json:"tokenUrl,omitempty"` // oauth2
|
||||||
|
Scopes map[string]string `json:"scopes,omitempty"` // oauth2
|
||||||
|
}{
|
||||||
|
Description: s.Description,
|
||||||
|
Type: s.Type,
|
||||||
|
Name: s.Name,
|
||||||
|
In: s.In,
|
||||||
|
Flow: s.Flow,
|
||||||
|
AuthorizationURL: s.AuthorizationURL,
|
||||||
|
TokenURL: s.TokenURL,
|
||||||
|
Scopes: s.Scopes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b2, err := json.Marshal(s.VendorExtensible)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return swag.ConcatJSON(b1, b2), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON marshal this from JSON
|
||||||
|
func (s *SecurityScheme) UnmarshalJSON(data []byte) error {
|
||||||
|
if err := json.Unmarshal(data, &s.SecuritySchemeProps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, &s.VendorExtensible)
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue