1package generator 2 3import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "sort" 8 "strconv" 9 "strings" 10 11 "github.com/go-openapi/analysis" 12 "github.com/go-openapi/spec" 13) 14 15// GenCommon contains common properties needed across 16// definitions, app and operations 17// TargetImportPath may be used by templates to import other (possibly 18// generated) packages in the generation path (e.g. relative to GOPATH). 19// TargetImportPath is NOT used by standard templates. 20type GenCommon struct { 21 Copyright string 22 TargetImportPath string 23} 24 25// GenDefinition contains all the properties to generate a 26// definition from a swagger spec 27type GenDefinition struct { 28 GenCommon 29 GenSchema 30 Package string 31 Imports map[string]string 32 DefaultImports map[string]string 33 ExtraSchemas GenSchemaList 34 DependsOn []string 35 External bool 36} 37 38// GenDefinitions represents a list of operations to generate 39// this implements a sort by operation id 40type GenDefinitions []GenDefinition 41 42func (g GenDefinitions) Len() int { return len(g) } 43func (g GenDefinitions) Less(i, j int) bool { return g[i].Name < g[j].Name } 44func (g GenDefinitions) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 45 46// GenSchemaList is a list of schemas for generation. 47// 48// It can be sorted by name to get a stable struct layout for 49// version control and such 50type GenSchemaList []GenSchema 51 52// GenSchema contains all the information needed to generate the code 53// for a schema 54type GenSchema struct { 55 resolvedType 56 sharedValidations 57 Example string 58 OriginalName string 59 Name string 60 Suffix string 61 Path string 62 ValueExpression string 63 IndexVar string 64 KeyVar string 65 Title string 66 Description string 67 Location string 68 ReceiverName string 69 Items *GenSchema 70 AllowsAdditionalItems bool 71 HasAdditionalItems bool 72 AdditionalItems *GenSchema 73 Object *GenSchema 74 XMLName string 75 CustomTag string 76 Properties GenSchemaList 77 AllOf GenSchemaList 78 HasAdditionalProperties bool 79 IsAdditionalProperties bool 80 AdditionalProperties *GenSchema 81 StrictAdditionalProperties bool 82 ReadOnly bool 83 IsVirtual bool 84 IsBaseType bool 85 HasBaseType bool 86 IsSubType bool 87 IsExported bool 88 DiscriminatorField string 89 DiscriminatorValue string 90 Discriminates map[string]string 91 Parents []string 92 IncludeValidator bool 93 IncludeModel bool 94 Default interface{} 95 WantsMarshalBinary bool // do we generate MarshalBinary interface? 96 StructTags []string 97 ExtraImports map[string]string // non-standard imports detected when using external types 98 ExternalDocs *spec.ExternalDocumentation 99} 100 101func (g GenSchema) renderMarshalTag() string { 102 if g.HasBaseType { 103 return "-" 104 } 105 106 var result strings.Builder 107 108 result.WriteString(g.OriginalName) 109 110 if !g.Required && g.IsEmptyOmitted { 111 result.WriteString(",omitempty") 112 } 113 114 if g.IsJSONString { 115 result.WriteString(",string") 116 } 117 118 return result.String() 119} 120 121// PrintTags takes care of rendering tags for a struct field 122func (g GenSchema) PrintTags() string { 123 tags := make(map[string]string, 3) 124 orderedTags := make([]string, 0, 3) 125 126 tags["json"] = g.renderMarshalTag() 127 orderedTags = append(orderedTags, "json") 128 129 if len(g.XMLName) > 0 { 130 if !g.Required && g.IsEmptyOmitted { 131 tags["xml"] = g.XMLName + ",omitempty" 132 } else { 133 tags["xml"] = g.XMLName 134 } 135 orderedTags = append(orderedTags, "xml") 136 } 137 138 // Add extra struct tags, only if the tag hasn't already been set, i.e. example. 139 // Extra struct tags have the same value has the `json` tag. 140 for _, tag := range g.StructTags { 141 if _, exists := tags[tag]; exists { 142 // dedupe 143 continue 144 } 145 146 if tag == "example" && len(g.Example) > 0 { 147 // only add example tag if it's contained in the struct tags 148 tags["example"] = g.Example // json representation of the example object 149 } else if tag == "description" && len(g.Description) > 0 { 150 tags["description"] = g.Description 151 } else { 152 tags[tag] = tags["json"] 153 } 154 155 orderedTags = append(orderedTags, tag) 156 } 157 158 // Assemble the tags in key value pairs with the value properly quoted. 159 kvPairs := make([]string, 0, len(orderedTags)+1) 160 for _, key := range orderedTags { 161 kvPairs = append(kvPairs, fmt.Sprintf("%s:%s", key, strconv.Quote(tags[key]))) 162 } 163 164 if len(g.CustomTag) > 0 { 165 kvPairs = append(kvPairs, g.CustomTag) 166 } 167 168 // Join the key value pairs by a space. 169 completeTag := strings.Join(kvPairs, " ") 170 171 // If the values contain a backtick, we cannot render the tag using backticks because Go does not support 172 // escaping backticks in raw string literals. 173 valuesHaveBacktick := false 174 for _, value := range tags { 175 if !strconv.CanBackquote(value) { 176 valuesHaveBacktick = true 177 break 178 } 179 } 180 181 if !valuesHaveBacktick { 182 return fmt.Sprintf("`%s`", completeTag) 183 } 184 185 // We have to escape the tag again to put it in a literal with double quotes as the tag format uses double quotes. 186 return strconv.Quote(completeTag) 187} 188 189// UnderlyingType tells the go type or the aliased go type 190func (g GenSchema) UnderlyingType() string { 191 if g.IsAliased { 192 return g.AliasedType 193 } 194 return g.GoType 195} 196 197// ToString returns a string conversion expression for the schema 198func (g GenSchema) ToString() string { 199 return g.resolvedType.ToString(g.ValueExpression) 200} 201 202func (g GenSchemaList) Len() int { return len(g) } 203func (g GenSchemaList) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 204func (g GenSchemaList) Less(i, j int) bool { 205 a, okA := g[i].Extensions[xOrder].(float64) 206 b, okB := g[j].Extensions[xOrder].(float64) 207 208 // If both properties have x-order defined, then the one with lower x-order is smaller 209 if okA && okB { 210 return a < b 211 } 212 213 // If only the first property has x-order defined, then it is smaller 214 if okA { 215 return true 216 } 217 218 // If only the second property has x-order defined, then it is smaller 219 if okB { 220 return false 221 } 222 223 // If neither property has x-order defined, then the one with lower lexicographic name is smaller 224 return g[i].Name < g[j].Name 225} 226 227type sharedValidations struct { 228 spec.SchemaValidations 229 230 HasValidations bool 231 HasContextValidations bool 232 Required bool 233 HasSliceValidations bool 234 ItemsEnum []interface{} 235 236 // NOTE: "patternProperties" and "dependencies" not supported by Swagger 2.0 237} 238 239// GenResponse represents a response object for code generation 240type GenResponse struct { 241 Package string 242 ModelsPackage string 243 ReceiverName string 244 Name string 245 Description string 246 247 IsSuccess bool 248 249 Code int 250 Method string 251 Path string 252 Headers GenHeaders 253 Schema *GenSchema 254 AllowsForStreaming bool 255 256 Imports map[string]string 257 DefaultImports map[string]string 258 259 Extensions map[string]interface{} 260 261 StrictResponders bool 262 OperationName string 263 Examples GenResponseExamples 264} 265 266// GenResponseExamples is a sortable collection []GenResponseExample 267type GenResponseExamples []GenResponseExample 268 269func (g GenResponseExamples) Len() int { return len(g) } 270func (g GenResponseExamples) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 271func (g GenResponseExamples) Less(i, j int) bool { return g[i].MediaType < g[j].MediaType } 272 273// GenResponseExample captures an example provided for a response for some mime type 274type GenResponseExample struct { 275 MediaType string 276 Example interface{} 277} 278 279// GenHeader represents a header on a response for code generation 280type GenHeader struct { 281 resolvedType 282 sharedValidations 283 284 Package string 285 ReceiverName string 286 IndexVar string 287 288 ID string 289 Name string 290 Path string 291 ValueExpression string 292 293 Title string 294 Description string 295 Default interface{} 296 HasDefault bool 297 298 CollectionFormat string 299 300 Child *GenItems 301 Parent *GenItems 302 303 Converter string 304 Formatter string 305 306 ZeroValue string 307} 308 309// ItemsDepth returns a string "items.items..." with as many items as the level of nesting of the array. 310// For a header objects it always returns "". 311func (h *GenHeader) ItemsDepth() string { 312 // NOTE: this is currently used by templates to generate explicit comments in nested structures 313 return "" 314} 315 316// ToString returns a string conversion expression for the header 317func (h GenHeader) ToString() string { 318 return h.resolvedType.ToString(h.ValueExpression) 319} 320 321// GenHeaders is a sorted collection of headers for codegen 322type GenHeaders []GenHeader 323 324func (g GenHeaders) Len() int { return len(g) } 325func (g GenHeaders) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 326func (g GenHeaders) Less(i, j int) bool { return g[i].Name < g[j].Name } 327 328// HasSomeDefaults returns true is at least one header has a default value set 329func (g GenHeaders) HasSomeDefaults() bool { 330 // NOTE: this is currently used by templates to avoid empty constructs 331 for _, header := range g { 332 if header.HasDefault { 333 return true 334 } 335 } 336 return false 337} 338 339// GenParameter is used to represent 340// a parameter or a header for code generation. 341type GenParameter struct { 342 resolvedType 343 sharedValidations 344 345 ID string 346 Name string 347 ModelsPackage string 348 Path string 349 ValueExpression string 350 IndexVar string 351 KeyVar string 352 ReceiverName string 353 Location string 354 Title string 355 Description string 356 Converter string 357 Formatter string 358 359 Schema *GenSchema 360 361 CollectionFormat string 362 363 Child *GenItems 364 Parent *GenItems 365 366 // Unused 367 // BodyParam *GenParameter 368 369 Default interface{} 370 HasDefault bool 371 ZeroValue string 372 AllowEmptyValue bool 373 374 // validation strategy for Body params, which may mix model and simple constructs. 375 // Distinguish the following cases: 376 // - HasSimpleBodyParams: body is an inline simple type 377 // - HasModelBodyParams: body is a model objectd 378 // - HasSimpleBodyItems: body is an inline array of simple type 379 // - HasModelBodyItems: body is an array of model objects 380 // - HasSimpleBodyMap: body is a map of simple objects (possibly arrays) 381 // - HasModelBodyMap: body is a map of model objects 382 HasSimpleBodyParams bool 383 HasModelBodyParams bool 384 HasSimpleBodyItems bool 385 HasModelBodyItems bool 386 HasSimpleBodyMap bool 387 HasModelBodyMap bool 388 389 Extensions map[string]interface{} 390} 391 392// IsQueryParam returns true when this parameter is a query param 393func (g *GenParameter) IsQueryParam() bool { 394 return g.Location == "query" 395} 396 397// IsPathParam returns true when this parameter is a path param 398func (g *GenParameter) IsPathParam() bool { 399 return g.Location == "path" 400} 401 402// IsFormParam returns true when this parameter is a form param 403func (g *GenParameter) IsFormParam() bool { 404 return g.Location == "formData" 405} 406 407// IsHeaderParam returns true when this parameter is a header param 408func (g *GenParameter) IsHeaderParam() bool { 409 return g.Location == "header" 410} 411 412// IsBodyParam returns true when this parameter is a body param 413func (g *GenParameter) IsBodyParam() bool { 414 return g.Location == "body" 415} 416 417// IsFileParam returns true when this parameter is a file param 418func (g *GenParameter) IsFileParam() bool { 419 return g.SwaggerType == "file" 420} 421 422// ItemsDepth returns a string "items.items..." with as many items as the level of nesting of the array. 423// For a parameter object, it always returns "". 424func (g *GenParameter) ItemsDepth() string { 425 // NOTE: this is currently used by templates to generate explicit comments in nested structures 426 return "" 427} 428 429// UnderlyingType tells the go type or the aliased go type 430func (g GenParameter) UnderlyingType() string { 431 return g.GoType 432} 433 434// ToString returns a string conversion expression for the parameter 435func (g GenParameter) ToString() string { 436 return g.resolvedType.ToString(g.ValueExpression) 437} 438 439// GenParameters represents a sorted parameter collection 440type GenParameters []GenParameter 441 442func (g GenParameters) Len() int { return len(g) } 443func (g GenParameters) Less(i, j int) bool { return g[i].Name < g[j].Name } 444func (g GenParameters) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 445 446// HasSomeDefaults returns true is at least one parameter has a default value set 447func (g GenParameters) HasSomeDefaults() bool { 448 // NOTE: this is currently used by templates to avoid empty constructs 449 for _, param := range g { 450 if param.HasDefault { 451 return true 452 } 453 } 454 return false 455} 456 457// GenItems represents the collection items for a collection parameter 458type GenItems struct { 459 sharedValidations 460 resolvedType 461 462 Name string 463 Path string 464 ValueExpression string 465 CollectionFormat string 466 Child *GenItems 467 Parent *GenItems 468 Converter string 469 Formatter string 470 471 Location string 472 IndexVar string 473 KeyVar string 474 475 // instructs generator to skip the splitting and parsing from CollectionFormat 476 SkipParse bool 477 // instructs generator that some nested structure needs an higher level loop index 478 NeedsIndex bool 479} 480 481// ItemsDepth returns a string "items.items..." with as many items as the level of nesting of the array. 482func (g *GenItems) ItemsDepth() string { 483 // NOTE: this is currently used by templates to generate explicit comments in nested structures 484 current := g 485 i := 1 486 for current.Parent != nil { 487 i++ 488 current = current.Parent 489 } 490 return strings.Repeat("items.", i) 491} 492 493// UnderlyingType tells the go type or the aliased go type 494func (g GenItems) UnderlyingType() string { 495 return g.GoType 496} 497 498// ToString returns a string conversion expression for the item 499func (g GenItems) ToString() string { 500 return g.resolvedType.ToString(g.ValueExpression) 501} 502 503// GenOperationGroup represents a named (tagged) group of operations 504type GenOperationGroup struct { 505 GenCommon 506 Name string 507 Operations GenOperations 508 509 Summary string 510 Description string 511 Imports map[string]string 512 DefaultImports map[string]string 513 RootPackage string 514 GenOpts *GenOpts 515 PackageAlias string 516} 517 518// GenOperationGroups is a sorted collection of operation groups 519type GenOperationGroups []GenOperationGroup 520 521func (g GenOperationGroups) Len() int { return len(g) } 522func (g GenOperationGroups) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 523func (g GenOperationGroups) Less(i, j int) bool { return g[i].Name < g[j].Name } 524 525// GenStatusCodeResponses a container for status code responses 526type GenStatusCodeResponses []GenResponse 527 528func (g GenStatusCodeResponses) Len() int { return len(g) } 529func (g GenStatusCodeResponses) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 530func (g GenStatusCodeResponses) Less(i, j int) bool { return g[i].Code < g[j].Code } 531 532// MarshalJSON marshals these responses to json 533// 534// This is used by DumpData. 535func (g GenStatusCodeResponses) MarshalJSON() ([]byte, error) { 536 if g == nil { 537 return nil, nil 538 } 539 responses := make(GenStatusCodeResponses, len(g)) 540 copy(responses, g) 541 // order marshalled output 542 sort.Sort(responses) 543 544 var buf bytes.Buffer 545 buf.WriteRune('{') 546 for i, v := range responses { 547 rb, err := json.Marshal(v) 548 if err != nil { 549 return nil, err 550 } 551 if i > 0 { 552 buf.WriteRune(',') 553 } 554 buf.WriteString(fmt.Sprintf("%q:", strconv.Itoa(v.Code))) 555 buf.Write(rb) 556 } 557 buf.WriteRune('}') 558 return buf.Bytes(), nil 559} 560 561// UnmarshalJSON unmarshals this GenStatusCodeResponses from json 562func (g *GenStatusCodeResponses) UnmarshalJSON(data []byte) error { 563 var dd map[string]GenResponse 564 if err := json.Unmarshal(data, &dd); err != nil { 565 return err 566 } 567 var gg GenStatusCodeResponses 568 for _, v := range dd { 569 gg = append(gg, v) 570 } 571 sort.Sort(gg) 572 *g = gg 573 return nil 574} 575 576// GenOperation represents an operation for code generation 577type GenOperation struct { 578 GenCommon 579 Package string 580 ReceiverName string 581 Name string 582 Summary string 583 Description string 584 Method string 585 Path string 586 BasePath string 587 Tags []string 588 UseTags bool 589 RootPackage string 590 591 Imports map[string]string 592 DefaultImports map[string]string 593 ExtraSchemas GenSchemaList 594 PackageAlias string 595 596 Authorized bool 597 Security []GenSecurityRequirements // resolved security requirements for the operation 598 SecurityDefinitions GenSecuritySchemes 599 SecurityRequirements []analysis.SecurityRequirement // original security requirements as per the spec (for doc) 600 Principal string 601 PrincipalIsNullable bool 602 603 SuccessResponse *GenResponse 604 SuccessResponses []GenResponse 605 Responses GenStatusCodeResponses 606 DefaultResponse *GenResponse 607 608 Params GenParameters 609 QueryParams GenParameters 610 PathParams GenParameters 611 HeaderParams GenParameters 612 FormParams GenParameters 613 HasQueryParams bool 614 HasPathParams bool 615 HasHeaderParams bool 616 HasFormParams bool 617 HasFormValueParams bool 618 HasFileParams bool 619 HasBodyParams bool 620 HasStreamingResponse bool 621 622 Schemes []string 623 ExtraSchemes []string 624 SchemeOverrides []string // original scheme overrides for operation, as per spec (for doc) 625 ExtraSchemeOverrides []string // original extra scheme overrides for operation, as per spec (for doc) 626 ProducesMediaTypes []string 627 ConsumesMediaTypes []string 628 TimeoutName string 629 630 Extensions map[string]interface{} 631 632 StrictResponders bool 633 ExternalDocs *spec.ExternalDocumentation 634 Produces []string // original produces for operation (for doc) 635 Consumes []string // original consumes for operation (for doc) 636} 637 638// GenOperations represents a list of operations to generate 639// this implements a sort by operation id 640type GenOperations []GenOperation 641 642func (g GenOperations) Len() int { return len(g) } 643func (g GenOperations) Less(i, j int) bool { return g[i].Name < g[j].Name } 644func (g GenOperations) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 645 646// GenApp represents all the meta data needed to generate an application 647// from a swagger spec 648type GenApp struct { 649 GenCommon 650 APIPackage string 651 ServerPackageAlias string 652 ImplementationPackageAlias string 653 APIPackageAlias string 654 Package string 655 ReceiverName string 656 Name string 657 Principal string 658 PrincipalIsNullable bool 659 DefaultConsumes string 660 DefaultProduces string 661 Host string 662 BasePath string 663 Info *spec.Info 664 ExternalDocs *spec.ExternalDocumentation 665 Tags []spec.Tag 666 Imports map[string]string 667 DefaultImports map[string]string 668 Schemes []string 669 ExtraSchemes []string 670 Consumes GenSerGroups 671 Produces GenSerGroups 672 SecurityDefinitions GenSecuritySchemes 673 SecurityRequirements []analysis.SecurityRequirement // original security requirements as per the spec (for doc) 674 Models []GenDefinition 675 Operations GenOperations 676 OperationGroups GenOperationGroups 677 SwaggerJSON string 678 // Embedded specs: this is important for when the generated server adds routes. 679 // NOTE: there is a distinct advantage to having this in runtime rather than generated code. 680 // We are not ever going to generate the router. 681 // If embedding spec is an issue (e.g. memory usage), this can be excluded with the --exclude-spec 682 // generation option. Alternative methods to serve spec (e.g. from disk, ...) may be implemented by 683 // adding a middleware to the generated API. 684 FlatSwaggerJSON string 685 ExcludeSpec bool 686 GenOpts *GenOpts 687} 688 689// UseGoStructFlags returns true when no strategy is specified or it is set to "go-flags" 690func (g *GenApp) UseGoStructFlags() bool { 691 if g.GenOpts == nil { 692 return true 693 } 694 return g.GenOpts.FlagStrategy == "" || g.GenOpts.FlagStrategy == "go-flags" 695} 696 697// UsePFlags returns true when the flag strategy is set to pflag 698func (g *GenApp) UsePFlags() bool { 699 return g.GenOpts != nil && strings.HasPrefix(g.GenOpts.FlagStrategy, "pflag") 700} 701 702// UseFlags returns true when the flag strategy is set to flag 703func (g *GenApp) UseFlags() bool { 704 return g.GenOpts != nil && strings.HasPrefix(g.GenOpts.FlagStrategy, "flag") 705} 706 707// UseIntermediateMode for https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29 708func (g *GenApp) UseIntermediateMode() bool { 709 return g.GenOpts != nil && g.GenOpts.CompatibilityMode == "intermediate" 710} 711 712// UseModernMode for https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility 713func (g *GenApp) UseModernMode() bool { 714 return g.GenOpts == nil || g.GenOpts.CompatibilityMode == "" || g.GenOpts.CompatibilityMode == "modern" 715} 716 717// GenSerGroups sorted representation of serializer groups 718type GenSerGroups []GenSerGroup 719 720func (g GenSerGroups) Len() int { return len(g) } 721func (g GenSerGroups) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 722func (g GenSerGroups) Less(i, j int) bool { return g[i].Name < g[j].Name } 723 724// GenSerGroup represents a group of serializers: this links a serializer to a list of 725// prioritized media types (mime). 726type GenSerGroup struct { 727 GenSerializer 728 729 // All media types for this serializer. The redundant representation allows for easier use in templates 730 AllSerializers GenSerializers 731} 732 733// GenSerializers sorted representation of serializers 734type GenSerializers []GenSerializer 735 736func (g GenSerializers) Len() int { return len(g) } 737func (g GenSerializers) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 738func (g GenSerializers) Less(i, j int) bool { return g[i].MediaType < g[j].MediaType } 739 740// GenSerializer represents a single serializer for a particular media type 741type GenSerializer struct { 742 AppName string // Application name 743 ReceiverName string 744 Name string // Name of the Producer/Consumer (e.g. json, yaml, txt, bin) 745 MediaType string // mime 746 Implementation string // func implementing the Producer/Consumer 747 Parameters []string // parameters supported by this serializer 748} 749 750// GenSecurityScheme represents a security scheme for code generation 751type GenSecurityScheme struct { 752 AppName string 753 ID string 754 Name string 755 ReceiverName string 756 IsBasicAuth bool 757 IsAPIKeyAuth bool 758 IsOAuth2 bool 759 Scopes []string 760 Source string 761 Principal string 762 PrincipalIsNullable bool 763 764 // from spec.SecurityScheme 765 Description string 766 Type string 767 In string 768 Flow string 769 AuthorizationURL string 770 TokenURL string 771 Extensions map[string]interface{} 772 ScopesDesc []GenSecurityScope 773} 774 775// GenSecuritySchemes sorted representation of serializers 776type GenSecuritySchemes []GenSecurityScheme 777 778func (g GenSecuritySchemes) Len() int { return len(g) } 779func (g GenSecuritySchemes) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 780func (g GenSecuritySchemes) Less(i, j int) bool { return g[i].ID < g[j].ID } 781 782// GenSecurityRequirement represents a security requirement for an operation 783type GenSecurityRequirement struct { 784 Name string 785 Scopes []string 786} 787 788// GenSecurityScope represents a scope descriptor for an OAuth2 security scheme 789type GenSecurityScope struct { 790 Name string 791 Description string 792} 793 794// GenSecurityRequirements represents a compounded security requirement specification. 795// In a []GenSecurityRequirements complete requirements specification, 796// outer elements are interpreted as optional requirements (OR), and 797// inner elements are interpreted as jointly required (AND). 798type GenSecurityRequirements []GenSecurityRequirement 799 800func (g GenSecurityRequirements) Len() int { return len(g) } 801func (g GenSecurityRequirements) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 802func (g GenSecurityRequirements) Less(i, j int) bool { return g[i].Name < g[j].Name } 803