aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/go-openapi/analysis/flatten.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-openapi/analysis/flatten.go')
-rw-r--r--vendor/github.com/go-openapi/analysis/flatten.go800
1 files changed, 0 insertions, 800 deletions
diff --git a/vendor/github.com/go-openapi/analysis/flatten.go b/vendor/github.com/go-openapi/analysis/flatten.go
deleted file mode 100644
index 703a0aa89..000000000
--- a/vendor/github.com/go-openapi/analysis/flatten.go
+++ /dev/null
@@ -1,800 +0,0 @@
-package analysis
-
-import (
- "fmt"
- "log"
- "net/http"
- "os"
- "path"
- "path/filepath"
- "sort"
- "strings"
-
- "strconv"
-
- "github.com/go-openapi/jsonpointer"
- swspec "github.com/go-openapi/spec"
- "github.com/go-openapi/swag"
-)
-
-// FlattenOpts configuration for flattening a swagger specification.
-type FlattenOpts struct {
- // If Expand is true, we skip flattening the spec and expand it instead
- Expand bool
- Spec *Spec
- BasePath string
-
- _ struct{} // require keys
-}
-
-// ExpandOpts creates a spec.ExpandOptions to configure expanding a specification document.
-func (f *FlattenOpts) ExpandOpts(skipSchemas bool) *swspec.ExpandOptions {
- return &swspec.ExpandOptions{RelativeBase: f.BasePath, SkipSchemas: skipSchemas}
-}
-
-// Swagger gets the swagger specification for this flatten operation
-func (f *FlattenOpts) Swagger() *swspec.Swagger {
- return f.Spec.spec
-}
-
-// Flatten an analyzed spec.
-//
-// To flatten a spec means:
-//
-// Expand the parameters, responses, path items, parameter items and header items.
-// Import external (http, file) references so they become internal to the document.
-// Move every inline schema to be a definition with an auto-generated name in a depth-first fashion.
-// Rewritten schemas get a vendor extension x-go-gen-location so we know in which package they need to be rendered.
-func Flatten(opts FlattenOpts) error {
- // Make sure opts.BasePath is an absolute path
- if !filepath.IsAbs(opts.BasePath) {
- cwd, _ := os.Getwd()
- opts.BasePath = filepath.Join(cwd, opts.BasePath)
- }
- // recursively expand responses, parameters, path items and items
- err := swspec.ExpandSpec(opts.Swagger(), &swspec.ExpandOptions{
- RelativeBase: opts.BasePath,
- SkipSchemas: !opts.Expand,
- })
- if err != nil {
- return err
- }
- opts.Spec.reload() // re-analyze
-
- // at this point there are no other references left but schemas
- if err := importExternalReferences(&opts); err != nil {
- return err
- }
- opts.Spec.reload() // re-analyze
-
- // rewrite the inline schemas (schemas that aren't simple types or arrays of simple types)
- if err := nameInlinedSchemas(&opts); err != nil {
- return err
- }
- opts.Spec.reload() // re-analyze
-
- // TODO: simplifiy known schema patterns to flat objects with properties?
- return nil
-}
-
-func nameInlinedSchemas(opts *FlattenOpts) error {
- namer := &inlineSchemaNamer{Spec: opts.Swagger(), Operations: opRefsByRef(gatherOperations(opts.Spec, nil))}
- depthFirst := sortDepthFirst(opts.Spec.allSchemas)
- for _, key := range depthFirst {
- sch := opts.Spec.allSchemas[key]
- if sch.Schema != nil && sch.Schema.Ref.String() == "" && !sch.TopLevel { // inline schema
- asch, err := Schema(SchemaOpts{Schema: sch.Schema, Root: opts.Swagger(), BasePath: opts.BasePath})
- if err != nil {
- return fmt.Errorf("schema analysis [%s]: %v", sch.Ref.String(), err)
- }
-
- if !asch.IsSimpleSchema { // complex schemas get moved
- if err := namer.Name(key, sch.Schema, asch); err != nil {
- return err
- }
- }
- }
- }
- return nil
-}
-
-var depthGroupOrder = []string{"sharedOpParam", "opParam", "codeResponse", "defaultResponse", "definition"}
-
-func sortDepthFirst(data map[string]SchemaRef) (sorted []string) {
- // group by category (shared params, op param, statuscode response, default response, definitions)
- // sort groups internally by number of parts in the key and lexical names
- // flatten groups into a single list of keys
- grouped := make(map[string]keys, len(data))
- for k := range data {
- split := keyParts(k)
- var pk string
- if split.IsSharedOperationParam() {
- pk = "sharedOpParam"
- }
- if split.IsOperationParam() {
- pk = "opParam"
- }
- if split.IsStatusCodeResponse() {
- pk = "codeResponse"
- }
- if split.IsDefaultResponse() {
- pk = "defaultResponse"
- }
- if split.IsDefinition() {
- pk = "definition"
- }
- grouped[pk] = append(grouped[pk], key{len(split), k})
- }
-
- for _, pk := range depthGroupOrder {
- res := grouped[pk]
- sort.Sort(res)
- for _, v := range res {
- sorted = append(sorted, v.Key)
- }
- }
-
- return
-}
-
-type key struct {
- Segments int
- Key string
-}
-type keys []key
-
-func (k keys) Len() int { return len(k) }
-func (k keys) Swap(i, j int) { k[i], k[j] = k[j], k[i] }
-func (k keys) Less(i, j int) bool {
- return k[i].Segments > k[j].Segments || (k[i].Segments == k[j].Segments && k[i].Key < k[j].Key)
-}
-
-type inlineSchemaNamer struct {
- Spec *swspec.Swagger
- Operations map[string]opRef
-}
-
-func opRefsByRef(oprefs map[string]opRef) map[string]opRef {
- result := make(map[string]opRef, len(oprefs))
- for _, v := range oprefs {
- result[v.Ref.String()] = v
- }
- return result
-}
-
-func (isn *inlineSchemaNamer) Name(key string, schema *swspec.Schema, aschema *AnalyzedSchema) error {
- if swspec.Debug {
- log.Printf("naming inlined schema at %s", key)
- }
-
- parts := keyParts(key)
- for _, name := range namesFromKey(parts, aschema, isn.Operations) {
- if name != "" {
- // create unique name
- newName := uniqifyName(isn.Spec.Definitions, swag.ToJSONName(name))
-
- // clone schema
- sch, err := cloneSchema(schema)
- if err != nil {
- return err
- }
-
- // replace values on schema
- if err := rewriteSchemaToRef(isn.Spec, key, swspec.MustCreateRef("#/definitions/"+newName)); err != nil {
- return fmt.Errorf("name inlined schema: %v", err)
- }
-
- sch.AddExtension("x-go-gen-location", genLocation(parts))
- // fmt.Printf("{\n %q,\n \"\",\n spec.MustCreateRef(%q),\n \"\",\n},\n", key, "#/definitions/"+newName)
- // save cloned schema to definitions
- saveSchema(isn.Spec, newName, sch)
- }
- }
- return nil
-}
-
-func genLocation(parts splitKey) string {
- if parts.IsOperation() {
- return "operations"
- }
- if parts.IsDefinition() {
- return "models"
- }
- return ""
-}
-
-func uniqifyName(definitions swspec.Definitions, name string) string {
- if name == "" {
- name = "oaiGen"
- }
- if len(definitions) == 0 {
- return name
- }
-
- unq := true
- for k := range definitions {
- if strings.ToLower(k) == strings.ToLower(name) {
- unq = false
- break
- }
- }
-
- if unq {
- return name
- }
-
- name += "OAIGen"
- var idx int
- unique := name
- _, known := definitions[unique]
- for known {
- idx++
- unique = fmt.Sprintf("%s%d", name, idx)
- _, known = definitions[unique]
- }
- return unique
-}
-
-func namesFromKey(parts splitKey, aschema *AnalyzedSchema, operations map[string]opRef) []string {
- var baseNames [][]string
- var startIndex int
- if parts.IsOperation() {
- // params
- if parts.IsOperationParam() || parts.IsSharedOperationParam() {
- piref := parts.PathItemRef()
- if piref.String() != "" && parts.IsOperationParam() {
- if op, ok := operations[piref.String()]; ok {
- startIndex = 5
- baseNames = append(baseNames, []string{op.ID, "params", "body"})
- }
- } else if parts.IsSharedOperationParam() {
- pref := parts.PathRef()
- for k, v := range operations {
- if strings.HasPrefix(k, pref.String()) {
- startIndex = 4
- baseNames = append(baseNames, []string{v.ID, "params", "body"})
- }
- }
- }
- }
- // responses
- if parts.IsOperationResponse() {
- piref := parts.PathItemRef()
- if piref.String() != "" {
- if op, ok := operations[piref.String()]; ok {
- startIndex = 6
- baseNames = append(baseNames, []string{op.ID, parts.ResponseName(), "body"})
- }
- }
- }
- }
-
- // definitions
- if parts.IsDefinition() {
- nm := parts.DefinitionName()
- if nm != "" {
- startIndex = 2
- baseNames = append(baseNames, []string{parts.DefinitionName()})
- }
- }
-
- var result []string
- for _, segments := range baseNames {
- nm := parts.BuildName(segments, startIndex, aschema)
- if nm != "" {
- result = append(result, nm)
- }
- }
- sort.Strings(result)
- return result
-}
-
-const (
- pths = "paths"
- responses = "responses"
- parameters = "parameters"
- definitions = "definitions"
-)
-
-var ignoredKeys map[string]struct{}
-
-func init() {
- ignoredKeys = map[string]struct{}{
- "schema": {},
- "properties": {},
- "not": {},
- "anyOf": {},
- "oneOf": {},
- }
-}
-
-type splitKey []string
-
-func (s splitKey) IsDefinition() bool {
- return len(s) > 1 && s[0] == definitions
-}
-
-func (s splitKey) DefinitionName() string {
- if !s.IsDefinition() {
- return ""
- }
- return s[1]
-}
-
-func (s splitKey) isKeyName(i int) bool {
- if i <= 0 {
- return false
- }
- count := 0
- for idx := i - 1; idx > 0; idx-- {
- if s[idx] != "properties" {
- break
- }
- count++
- }
-
- if count%2 != 0 {
- return true
- }
- return false
-}
-
-func (s splitKey) BuildName(segments []string, startIndex int, aschema *AnalyzedSchema) string {
- for i, part := range s[startIndex:] {
- if _, ignored := ignoredKeys[part]; !ignored || s.isKeyName(startIndex+i) {
- if part == "items" || part == "additionalItems" {
- if aschema.IsTuple || aschema.IsTupleWithExtra {
- segments = append(segments, "tuple")
- } else {
- segments = append(segments, "items")
- }
- if part == "additionalItems" {
- segments = append(segments, part)
- }
- continue
- }
- segments = append(segments, part)
- }
- }
- return strings.Join(segments, " ")
-}
-
-func (s splitKey) IsOperation() bool {
- return len(s) > 1 && s[0] == pths
-}
-
-func (s splitKey) IsSharedOperationParam() bool {
- return len(s) > 2 && s[0] == pths && s[2] == parameters
-}
-
-func (s splitKey) IsOperationParam() bool {
- return len(s) > 3 && s[0] == pths && s[3] == parameters
-}
-
-func (s splitKey) IsOperationResponse() bool {
- return len(s) > 3 && s[0] == pths && s[3] == responses
-}
-
-func (s splitKey) IsDefaultResponse() bool {
- return len(s) > 4 && s[0] == pths && s[3] == responses && s[4] == "default"
-}
-
-func (s splitKey) IsStatusCodeResponse() bool {
- isInt := func() bool {
- _, err := strconv.Atoi(s[4])
- return err == nil
- }
- return len(s) > 4 && s[0] == pths && s[3] == responses && isInt()
-}
-
-func (s splitKey) ResponseName() string {
- if s.IsStatusCodeResponse() {
- code, _ := strconv.Atoi(s[4])
- return http.StatusText(code)
- }
- if s.IsDefaultResponse() {
- return "Default"
- }
- return ""
-}
-
-var validMethods map[string]struct{}
-
-func init() {
- validMethods = map[string]struct{}{
- "GET": {},
- "HEAD": {},
- "OPTIONS": {},
- "PATCH": {},
- "POST": {},
- "PUT": {},
- "DELETE": {},
- }
-}
-
-func (s splitKey) PathItemRef() swspec.Ref {
- if len(s) < 3 {
- return swspec.Ref{}
- }
- pth, method := s[1], s[2]
- if _, validMethod := validMethods[strings.ToUpper(method)]; !validMethod && !strings.HasPrefix(method, "x-") {
- return swspec.Ref{}
- }
- return swspec.MustCreateRef("#" + path.Join("/", pths, jsonpointer.Escape(pth), strings.ToUpper(method)))
-}
-
-func (s splitKey) PathRef() swspec.Ref {
- if !s.IsOperation() {
- return swspec.Ref{}
- }
- return swspec.MustCreateRef("#" + path.Join("/", pths, jsonpointer.Escape(s[1])))
-}
-
-func keyParts(key string) splitKey {
- var res []string
- for _, part := range strings.Split(key[1:], "/") {
- if part != "" {
- res = append(res, jsonpointer.Unescape(part))
- }
- }
- return res
-}
-
-func rewriteSchemaToRef(spec *swspec.Swagger, key string, ref swspec.Ref) error {
- if swspec.Debug {
- log.Printf("rewriting schema to ref for %s with %s", key, ref.String())
- }
- pth := key[1:]
- ptr, err := jsonpointer.New(pth)
- if err != nil {
- return err
- }
-
- value, _, err := ptr.Get(spec)
- if err != nil {
- return err
- }
-
- switch refable := value.(type) {
- case *swspec.Schema:
- return rewriteParentRef(spec, key, ref)
- case *swspec.SchemaOrBool:
- if refable.Schema != nil {
- refable.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
- }
- case *swspec.SchemaOrArray:
- if refable.Schema != nil {
- refable.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
- }
- case swspec.Schema:
- return rewriteParentRef(spec, key, ref)
- default:
- return fmt.Errorf("no schema with ref found at %s for %T", key, value)
- }
-
- return nil
-}
-
-func rewriteParentRef(spec *swspec.Swagger, key string, ref swspec.Ref) error {
- pth := key[1:]
- parent, entry := path.Dir(pth), path.Base(pth)
- if swspec.Debug {
- log.Println("getting schema holder at:", parent)
- }
-
- pptr, err := jsonpointer.New(parent)
- if err != nil {
- return err
- }
- pvalue, _, err := pptr.Get(spec)
- if err != nil {
- return fmt.Errorf("can't get parent for %s: %v", parent, err)
- }
- if swspec.Debug {
- log.Printf("rewriting holder for %T", pvalue)
- }
-
- switch container := pvalue.(type) {
- case swspec.Response:
- if err := rewriteParentRef(spec, "#"+parent, ref); err != nil {
- return err
- }
-
- case *swspec.Response:
- container.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
-
- case *swspec.Responses:
- statusCode, err := strconv.Atoi(entry)
- if err != nil {
- return fmt.Errorf("%s not a number: %v", pth, err)
- }
- resp := container.StatusCodeResponses[statusCode]
- resp.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
- container.StatusCodeResponses[statusCode] = resp
-
- case map[string]swspec.Response:
- resp := container[entry]
- resp.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
- container[entry] = resp
-
- case swspec.Parameter:
- if err := rewriteParentRef(spec, "#"+parent, ref); err != nil {
- return err
- }
-
- case map[string]swspec.Parameter:
- param := container[entry]
- param.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
- container[entry] = param
-
- case []swspec.Parameter:
- idx, err := strconv.Atoi(entry)
- if err != nil {
- return fmt.Errorf("%s not a number: %v", pth, err)
- }
- param := container[idx]
- param.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
- container[idx] = param
-
- case swspec.Definitions:
- container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
-
- case map[string]swspec.Schema:
- container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
-
- case []swspec.Schema:
- idx, err := strconv.Atoi(entry)
- if err != nil {
- return fmt.Errorf("%s not a number: %v", pth, err)
- }
- container[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
-
- case *swspec.SchemaOrArray:
- idx, err := strconv.Atoi(entry)
- if err != nil {
- return fmt.Errorf("%s not a number: %v", pth, err)
- }
- container.Schemas[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
- default:
- return fmt.Errorf("unhandled parent schema rewrite %s (%T)", key, pvalue)
- }
- return nil
-}
-
-func cloneSchema(schema *swspec.Schema) (*swspec.Schema, error) {
- var sch swspec.Schema
- if err := swag.FromDynamicJSON(schema, &sch); err != nil {
- return nil, fmt.Errorf("name inlined schema: %v", err)
- }
- return &sch, nil
-}
-
-func importExternalReferences(opts *FlattenOpts) error {
- groupedRefs := reverseIndexForSchemaRefs(opts)
-
- for refStr, entry := range groupedRefs {
- if !entry.Ref.HasFragmentOnly {
- if swspec.Debug {
- log.Printf("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr)
- }
- // resolve to actual schema
- sch := new(swspec.Schema)
- sch.Ref = entry.Ref
- expandOpts := swspec.ExpandOptions{
- RelativeBase: opts.BasePath,
- SkipSchemas: false,
- }
- err := swspec.ExpandSchemaWithBasePath(sch, nil, &expandOpts)
- if err != nil {
- return err
- }
- if sch == nil {
- return fmt.Errorf("no schema found at %s for [%s]", refStr, strings.Join(entry.Keys, ", "))
- }
- if swspec.Debug {
- log.Printf("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr)
- }
-
- // generate a unique name
- newName := uniqifyName(opts.Swagger().Definitions, nameFromRef(entry.Ref))
- if swspec.Debug {
- log.Printf("new name for [%s]: %s", strings.Join(entry.Keys, ", "), newName)
- }
-
- // rewrite the external refs to local ones
- for _, key := range entry.Keys {
- if err := updateRef(opts.Swagger(), key, swspec.MustCreateRef("#"+path.Join("/definitions", newName))); err != nil {
- return err
- }
- }
-
- // add the resolved schema to the definitions
- saveSchema(opts.Swagger(), newName, sch)
- }
- }
- return nil
-}
-
-type refRevIdx struct {
- Ref swspec.Ref
- Keys []string
-}
-
-func reverseIndexForSchemaRefs(opts *FlattenOpts) map[string]refRevIdx {
- collected := make(map[string]refRevIdx)
- for key, schRef := range opts.Spec.references.schemas {
- if entry, ok := collected[schRef.String()]; ok {
- entry.Keys = append(entry.Keys, key)
- collected[schRef.String()] = entry
- } else {
- collected[schRef.String()] = refRevIdx{
- Ref: schRef,
- Keys: []string{key},
- }
- }
- }
- return collected
-}
-
-func nameFromRef(ref swspec.Ref) string {
- u := ref.GetURL()
- if u.Fragment != "" {
- return swag.ToJSONName(path.Base(u.Fragment))
- }
- if u.Path != "" {
- bn := path.Base(u.Path)
- if bn != "" && bn != "/" {
- ext := path.Ext(bn)
- if ext != "" {
- return swag.ToJSONName(bn[:len(bn)-len(ext)])
- }
- return swag.ToJSONName(bn)
- }
- }
- return swag.ToJSONName(strings.Replace(u.Host, ".", " ", -1))
-}
-
-func saveSchema(spec *swspec.Swagger, name string, schema *swspec.Schema) {
- if schema == nil {
- return
- }
- if spec.Definitions == nil {
- spec.Definitions = make(map[string]swspec.Schema, 150)
- }
- spec.Definitions[name] = *schema
-}
-
-func updateRef(spec *swspec.Swagger, key string, ref swspec.Ref) error {
- if swspec.Debug {
- log.Printf("updating ref for %s with %s", key, ref.String())
- }
- pth := key[1:]
- ptr, err := jsonpointer.New(pth)
- if err != nil {
- return err
- }
-
- value, _, err := ptr.Get(spec)
- if err != nil {
- return err
- }
-
- switch refable := value.(type) {
- case *swspec.Schema:
- refable.Ref = ref
- case *swspec.SchemaOrBool:
- if refable.Schema != nil {
- refable.Schema.Ref = ref
- }
- case *swspec.SchemaOrArray:
- if refable.Schema != nil {
- refable.Schema.Ref = ref
- }
- case swspec.Schema:
- parent, entry := path.Dir(pth), path.Base(pth)
- if swspec.Debug {
- log.Println("getting schema holder at:", parent)
- }
-
- pptr, err := jsonpointer.New(parent)
- if err != nil {
- return err
- }
- pvalue, _, err := pptr.Get(spec)
- if err != nil {
- return fmt.Errorf("can't get parent for %s: %v", parent, err)
- }
-
- switch container := pvalue.(type) {
- case swspec.Definitions:
- container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
-
- case map[string]swspec.Schema:
- container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
-
- case []swspec.Schema:
- idx, err := strconv.Atoi(entry)
- if err != nil {
- return fmt.Errorf("%s not a number: %v", pth, err)
- }
- container[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
-
- case *swspec.SchemaOrArray:
- idx, err := strconv.Atoi(entry)
- if err != nil {
- return fmt.Errorf("%s not a number: %v", pth, err)
- }
- container.Schemas[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
-
- }
-
- default:
- return fmt.Errorf("no schema with ref found at %s for %T", key, value)
- }
-
- return nil
-}
-
-func containsString(names []string, name string) bool {
- for _, nm := range names {
- if nm == name {
- return true
- }
- }
- return false
-}
-
-type opRef struct {
- Method string
- Path string
- Key string
- ID string
- Op *swspec.Operation
- Ref swspec.Ref
-}
-
-type opRefs []opRef
-
-func (o opRefs) Len() int { return len(o) }
-func (o opRefs) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
-func (o opRefs) Less(i, j int) bool { return o[i].Key < o[j].Key }
-
-func gatherOperations(specDoc *Spec, operationIDs []string) map[string]opRef {
- var oprefs opRefs
-
- for method, pathItem := range specDoc.Operations() {
- for pth, operation := range pathItem {
- vv := *operation
- oprefs = append(oprefs, opRef{
- Key: swag.ToGoName(strings.ToLower(method) + " " + pth),
- Method: method,
- Path: pth,
- ID: vv.ID,
- Op: &vv,
- Ref: swspec.MustCreateRef("#" + path.Join("/paths", jsonpointer.Escape(pth), method)),
- })
- }
- }
-
- sort.Sort(oprefs)
-
- operations := make(map[string]opRef)
- for _, opr := range oprefs {
- nm := opr.ID
- if nm == "" {
- nm = opr.Key
- }
-
- oo, found := operations[nm]
- if found && oo.Method != opr.Method && oo.Path != opr.Path {
- nm = opr.Key
- }
- if len(operationIDs) == 0 || containsString(operationIDs, opr.ID) || containsString(operationIDs, nm) {
- opr.ID = nm
- opr.Op.ID = nm
- operations[nm] = opr
- }
- }
-
- return operations
-}