github.com/emreu/go-swagger@v0.22.1/generator/types.go (about) 1 // Copyright 2015 go-swagger maintainers 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package generator 16 17 import ( 18 "fmt" 19 "log" 20 "path" 21 "path/filepath" 22 "strings" 23 24 "github.com/go-openapi/loads" 25 "github.com/go-openapi/spec" 26 "github.com/go-openapi/swag" 27 "github.com/kr/pretty" 28 ) 29 30 const ( 31 iface = "interface{}" 32 array = "array" 33 file = "file" 34 number = "number" 35 integer = "integer" 36 boolean = "boolean" 37 str = "string" 38 object = "object" 39 binary = "binary" 40 sHTTP = "http" 41 body = "body" 42 ) 43 44 // Extensions supported by go-swagger 45 const ( 46 xClass = "x-class" // class name used by discriminator 47 xGoCustomTag = "x-go-custom-tag" // additional tag for serializers on struct fields 48 xGoName = "x-go-name" // name of the generated go variable 49 xGoType = "x-go-type" // reuse existing type (do not generate) 50 xIsNullable = "x-isnullable" 51 xNullable = "x-nullable" // turns the schema into a pointer 52 xOmitEmpty = "x-omitempty" 53 xSchemes = "x-schemes" // additional schemes supported for operations (server generation) 54 xOrder = "x-order" // sort order for properties (or any schema) 55 ) 56 57 // swaggerTypeMapping contains a mapping from go type to swagger type or format 58 var swaggerTypeName map[string]string 59 60 func init() { 61 swaggerTypeName = make(map[string]string) 62 for k, v := range typeMapping { 63 swaggerTypeName[v] = k 64 } 65 } 66 67 func simpleResolvedType(tn, fmt string, items *spec.Items) (result resolvedType) { 68 result.SwaggerType = tn 69 result.SwaggerFormat = fmt 70 71 if tn == file { 72 // special case of swagger type "file", rendered as io.ReadCloser interface 73 result.IsPrimitive = true 74 result.GoType = formatMapping[str][binary] 75 result.IsStream = true 76 return 77 } 78 79 if fmt != "" { 80 fmtn := strings.Replace(fmt, "-", "", -1) 81 if fmm, ok := formatMapping[tn]; ok { 82 if tpe, ok := fmm[fmtn]; ok { 83 result.GoType = tpe 84 result.IsPrimitive = true 85 _, result.IsCustomFormatter = customFormatters[tpe] 86 // special case of swagger format "binary", rendered as io.ReadCloser interface 87 // TODO(fredbi): should set IsCustomFormatter=false when binary 88 result.IsStream = fmt == binary 89 return 90 } 91 } 92 } 93 94 if tpe, ok := typeMapping[tn]; ok { 95 result.GoType = tpe 96 _, result.IsPrimitive = primitives[tpe] 97 result.IsPrimitive = ok 98 return 99 } 100 101 if tn == array { 102 result.IsArray = true 103 result.IsPrimitive = false 104 result.IsCustomFormatter = false 105 result.IsNullable = false 106 if items == nil { 107 result.GoType = "[]" + iface 108 return 109 } 110 res := simpleResolvedType(items.Type, items.Format, items.Items) 111 result.GoType = "[]" + res.GoType 112 return 113 } 114 result.GoType = tn 115 _, result.IsPrimitive = primitives[tn] 116 return 117 } 118 119 func typeForHeader(header spec.Header) resolvedType { 120 return simpleResolvedType(header.Type, header.Format, header.Items) 121 } 122 123 func newTypeResolver(pkg string, doc *loads.Document) *typeResolver { 124 resolver := typeResolver{ModelsPackage: pkg, Doc: doc} 125 resolver.KnownDefs = make(map[string]struct{}, len(doc.Spec().Definitions)) 126 for k, sch := range doc.Spec().Definitions { 127 tpe, _, _ := knownDefGoType(k, sch, nil) 128 resolver.KnownDefs[tpe] = struct{}{} 129 } 130 return &resolver 131 } 132 133 // knownDefGoType returns go type, package and package alias for definition 134 func knownDefGoType(def string, schema spec.Schema, clear func(string) string) (string, string, string) { 135 debugLog("known def type: %q", def) 136 ext := schema.Extensions 137 if nm, ok := ext.GetString(xGoName); ok { 138 if clear == nil { 139 debugLog("known def type %s no clear: %q", xGoName, nm) 140 return nm, "", "" 141 } 142 debugLog("known def type %s clear: %q -> %q", xGoName, nm, clear(nm)) 143 return clear(nm), "", "" 144 } 145 v, ok := ext[xGoType] 146 if !ok { 147 if clear == nil { 148 debugLog("known def type no clear: %q", def) 149 return def, "", "" 150 } 151 debugLog("known def type clear: %q -> %q", def, clear(def)) 152 return clear(def), "", "" 153 } 154 xt := v.(map[string]interface{}) 155 t := xt["type"].(string) 156 impIface, ok := xt["import"] 157 158 if !ok { 159 return t, "", "" 160 } 161 162 imp := impIface.(map[string]interface{}) 163 pkg := imp["package"].(string) 164 al, ok := imp["alias"] 165 var alias string 166 if ok { 167 alias = al.(string) 168 } else { 169 alias = path.Base(pkg) 170 } 171 debugLog("known def type %s no clear: %q: pkg=%s, alias=%s", xGoType, alias+"."+t, pkg, alias) 172 return alias + "." + t, pkg, alias 173 } 174 175 type typeResolver struct { 176 Doc *loads.Document 177 ModelsPackage string 178 ModelName string 179 KnownDefs map[string]struct{} 180 // unexported fields 181 keepDefinitionsPkg string 182 knownDefsKept map[string]struct{} 183 } 184 185 // NewWithModelName clones a type resolver and specifies a new model name 186 func (t *typeResolver) NewWithModelName(name string) *typeResolver { 187 tt := newTypeResolver(t.ModelsPackage, t.Doc) 188 tt.ModelName = name 189 190 // propagates kept definitions 191 tt.keepDefinitionsPkg = t.keepDefinitionsPkg 192 tt.knownDefsKept = t.knownDefsKept 193 return tt 194 } 195 196 // withKeepDefinitionsPackage instructs the type resolver to keep previously resolved package name for 197 // definitions known at the moment it is first called. 198 func (t *typeResolver) withKeepDefinitionsPackage(definitionsPackage string) *typeResolver { 199 t.keepDefinitionsPkg = definitionsPackage 200 t.knownDefsKept = make(map[string]struct{}, len(t.KnownDefs)) 201 for k := range t.KnownDefs { 202 t.knownDefsKept[k] = struct{}{} 203 } 204 return t 205 } 206 207 // IsNullable hints the generator as to render the type with a pointer or not. 208 // 209 // A schema is deemed nullable (i.e. rendered by a pointer) when: 210 // - a custom extension says it has to be so 211 // - it is an object with properties 212 // - it is a composed object (allOf) 213 // 214 // The interpretation of Required as a mean to make a type nullable is carried on elsewhere. 215 func (t *typeResolver) IsNullable(schema *spec.Schema) bool { 216 nullable := t.isNullable(schema) 217 return nullable || len(schema.AllOf) > 0 218 } 219 220 func (t *typeResolver) resolveSchemaRef(schema *spec.Schema, isRequired bool) (returns bool, result resolvedType, err error) { 221 if schema.Ref.String() != "" { 222 debugLog("resolving ref (anon: %t, req: %t) %s", false, isRequired, schema.Ref.String()) 223 returns = true 224 var ref *spec.Schema 225 var er error 226 227 ref, er = spec.ResolveRef(t.Doc.Spec(), &schema.Ref) 228 if er != nil { 229 debugLog("error resolving ref %s: %v", schema.Ref.String(), er) 230 err = er 231 return 232 } 233 res, er := t.ResolveSchema(ref, false, isRequired) 234 if er != nil { 235 err = er 236 return 237 } 238 result = res 239 240 tn := filepath.Base(schema.Ref.GetURL().Fragment) 241 tpe, pkg, alias := knownDefGoType(tn, *ref, t.goTypeName) 242 debugLog("type name %s, package %s, alias %s", tpe, pkg, alias) 243 if tpe != "" { 244 result.GoType = tpe 245 result.Pkg = pkg 246 result.PkgAlias = alias 247 } 248 result.HasDiscriminator = res.HasDiscriminator 249 result.IsBaseType = result.HasDiscriminator 250 result.IsNullable = t.IsNullable(ref) 251 //result.IsAliased = true 252 return 253 254 } 255 return 256 } 257 258 func (t *typeResolver) inferAliasing(result *resolvedType, schema *spec.Schema, isAnonymous bool, isRequired bool) { 259 if !isAnonymous && t.ModelName != "" { 260 result.AliasedType = result.GoType 261 result.IsAliased = true 262 result.GoType = t.goTypeName(t.ModelName) 263 } 264 } 265 266 func (t *typeResolver) resolveFormat(schema *spec.Schema, isAnonymous bool, isRequired bool) (returns bool, result resolvedType, err error) { 267 268 if schema.Format != "" { 269 // defaults to string 270 result.SwaggerType = str 271 if len(schema.Type) > 0 { 272 result.SwaggerType = schema.Type[0] 273 } 274 275 debugLog("resolving format (anon: %t, req: %t)", isAnonymous, isRequired) 276 schFmt := strings.Replace(schema.Format, "-", "", -1) 277 if fmm, ok := formatMapping[result.SwaggerType]; ok { 278 if tpe, ok := fmm[schFmt]; ok { 279 returns = true 280 result.GoType = tpe 281 _, result.IsCustomFormatter = customFormatters[tpe] 282 } 283 } 284 if tpe, ok := typeMapping[schFmt]; !returns && ok { 285 returns = true 286 result.GoType = tpe 287 _, result.IsCustomFormatter = customFormatters[tpe] 288 } 289 290 result.SwaggerFormat = schema.Format 291 t.inferAliasing(&result, schema, isAnonymous, isRequired) 292 // special case of swagger format "binary", rendered as io.ReadCloser interface and is therefore not a primitive type 293 // TODO: should set IsCustomFormatter=false in this case. 294 result.IsPrimitive = schFmt != binary 295 result.IsStream = schFmt == binary 296 // propagate extensions in resolvedType 297 result.Extensions = schema.Extensions 298 299 switch result.SwaggerType { 300 case str: 301 result.IsNullable = nullableStrfmt(schema, isRequired) 302 case number, integer: 303 result.IsNullable = nullableNumber(schema, isRequired) 304 default: 305 result.IsNullable = t.IsNullable(schema) 306 } 307 } 308 return 309 } 310 311 func (t *typeResolver) isNullable(schema *spec.Schema) bool { 312 check := func(extension string) (bool, bool) { 313 v, found := schema.Extensions[extension] 314 nullable, cast := v.(bool) 315 return nullable, found && cast 316 } 317 318 if nullable, ok := check(xIsNullable); ok { 319 return nullable 320 } 321 if nullable, ok := check(xNullable); ok { 322 return nullable 323 } 324 return len(schema.Properties) > 0 325 } 326 327 func setIsEmptyOmitted(result *resolvedType, schema *spec.Schema, tpe string) { 328 defaultValue := true 329 if tpe == array { 330 defaultValue = false 331 } 332 v, found := schema.Extensions[xOmitEmpty] 333 if !found { 334 result.IsEmptyOmitted = defaultValue 335 return 336 } 337 338 omitted, cast := v.(bool) 339 result.IsEmptyOmitted = omitted && cast 340 } 341 342 func (t *typeResolver) firstType(schema *spec.Schema) string { 343 if len(schema.Type) == 0 || schema.Type[0] == "" { 344 return object 345 } 346 if len(schema.Type) > 1 { 347 // JSON-Schema multiple types, e.g. {"type": [ "object", "array" ]} are not supported. 348 // TODO: should keep the first _supported_ type, e.g. skip null 349 log.Printf("warning: JSON-Schema type definition as array with several types is not supported in %#v. Taking the first type: %s", schema.Type, schema.Type[0]) 350 } 351 return schema.Type[0] 352 } 353 354 func (t *typeResolver) resolveArray(schema *spec.Schema, isAnonymous, isRequired bool) (result resolvedType, err error) { 355 debugLog("resolving array (anon: %t, req: %t)", isAnonymous, isRequired) 356 357 result.IsArray = true 358 result.IsNullable = false 359 360 if schema.AdditionalItems != nil { 361 result.HasAdditionalItems = (schema.AdditionalItems.Allows || schema.AdditionalItems.Schema != nil) 362 } 363 364 if schema.Items == nil { 365 result.GoType = "[]" + iface 366 result.SwaggerType = array 367 result.SwaggerFormat = "" 368 t.inferAliasing(&result, schema, isAnonymous, isRequired) 369 370 return 371 } 372 373 if len(schema.Items.Schemas) > 0 { 374 result.IsArray = false 375 result.IsTuple = true 376 result.SwaggerType = array 377 result.SwaggerFormat = "" 378 t.inferAliasing(&result, schema, isAnonymous, isRequired) 379 380 return 381 } 382 383 rt, er := t.ResolveSchema(schema.Items.Schema, true, false) 384 if er != nil { 385 err = er 386 return 387 } 388 // override the general nullability rule from ResolveSchema(): 389 // only complex items are nullable (when not discriminated, not forced by x-nullable) 390 rt.IsNullable = t.IsNullable(schema.Items.Schema) && !rt.HasDiscriminator 391 result.GoType = "[]" + rt.GoType 392 if rt.IsNullable && !strings.HasPrefix(rt.GoType, "*") { 393 result.GoType = "[]*" + rt.GoType 394 } 395 396 result.ElemType = &rt 397 result.SwaggerType = array 398 result.SwaggerFormat = "" 399 t.inferAliasing(&result, schema, isAnonymous, isRequired) 400 result.Extensions = schema.Extensions 401 402 return 403 } 404 405 func (t *typeResolver) goTypeName(nm string) string { 406 if len(t.knownDefsKept) > 0 { 407 // if a definitions package has been defined, already resolved definitions are 408 // always resolved against their original package (e.g. "models"), and not the 409 // current package. 410 // This allows complex anonymous extra schemas to reuse known definitions generated in another package. 411 if _, ok := t.knownDefsKept[nm]; ok { 412 return strings.Join([]string{t.keepDefinitionsPkg, swag.ToGoName(nm)}, ".") 413 } 414 } 415 416 if t.ModelsPackage == "" { 417 return swag.ToGoName(nm) 418 } 419 if _, ok := t.KnownDefs[nm]; ok { 420 return strings.Join([]string{t.ModelsPackage, swag.ToGoName(nm)}, ".") 421 } 422 return swag.ToGoName(nm) 423 } 424 425 func (t *typeResolver) resolveObject(schema *spec.Schema, isAnonymous bool) (result resolvedType, err error) { 426 debugLog("resolving object %s (anon: %t, req: %t)", t.ModelName, isAnonymous, false) 427 428 result.IsAnonymous = isAnonymous 429 430 result.IsBaseType = schema.Discriminator != "" 431 if !isAnonymous { 432 result.SwaggerType = object 433 tpe, pkg, alias := knownDefGoType(t.ModelName, *schema, t.goTypeName) 434 result.GoType = tpe 435 result.Pkg = pkg 436 result.PkgAlias = alias 437 } 438 if len(schema.AllOf) > 0 { 439 result.GoType = t.goTypeName(t.ModelName) 440 result.IsComplexObject = true 441 var isNullable bool 442 for _, p := range schema.AllOf { 443 if t.IsNullable(&p) { 444 isNullable = true 445 } 446 } 447 result.IsNullable = isNullable 448 result.SwaggerType = object 449 return 450 } 451 452 // if this schema has properties, build a map of property name to 453 // resolved type, this should also flag the object as anonymous, 454 // when a ref is found, the anonymous flag will be reset 455 if len(schema.Properties) > 0 { 456 result.IsNullable = t.IsNullable(schema) 457 result.IsComplexObject = true 458 // no return here, still need to check for additional properties 459 } 460 461 // account for additional properties 462 if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil { 463 sch := schema.AdditionalProperties.Schema 464 et, er := t.ResolveSchema(sch, sch.Ref.String() == "", false) 465 if er != nil { 466 err = er 467 return 468 } 469 470 result.IsMap = !result.IsComplexObject 471 472 result.SwaggerType = object 473 474 // only complex map elements are nullable (when not forced by x-nullable) 475 // TODO: figure out if required to check when not discriminated like arrays? 476 et.IsNullable = t.isNullable(schema.AdditionalProperties.Schema) 477 if et.IsNullable { 478 result.GoType = "map[string]*" + et.GoType 479 } else { 480 result.GoType = "map[string]" + et.GoType 481 } 482 483 // Resolving nullability conflicts for: 484 // - map[][]...[]{items} 485 // - map[]{aliased type} 486 // 487 // when IsMap is true and the type is a distinct definition, 488 // aliased type or anonymous construct generated independently. 489 // 490 // IsMapNullOverride is to be handled by the generator for special cases 491 // where the map element is considered non nullable and the element itself is. 492 // 493 // This allows to appreciate nullability according to the context 494 needsOverride := result.IsMap && (et.IsArray || (sch.Ref.String() != "" || et.IsAliased || et.IsAnonymous)) 495 496 if needsOverride { 497 var er error 498 if et.IsArray { 499 var it resolvedType 500 s := sch 501 // resolve the last items after nested arrays 502 for s.Items != nil && s.Items.Schema != nil { 503 it, er = t.ResolveSchema(s.Items.Schema, sch.Ref.String() == "", false) 504 if er != nil { 505 return 506 } 507 s = s.Items.Schema 508 } 509 // mark an override when nullable status conflicts, i.e. when the original type is not already nullable 510 if !it.IsAnonymous || it.IsAnonymous && it.IsNullable { 511 result.IsMapNullOverride = true 512 } 513 } else { 514 // this locks the generator on the local nullability status 515 result.IsMapNullOverride = true 516 } 517 } 518 519 t.inferAliasing(&result, schema, isAnonymous, false) 520 result.ElemType = &et 521 return 522 } 523 524 if len(schema.Properties) > 0 { 525 return 526 } 527 528 // an object without property and without AdditionalProperties schema is rendered as interface{} 529 result.GoType = iface 530 result.IsMap = true 531 result.SwaggerType = object 532 result.IsNullable = false 533 result.IsInterface = len(schema.Properties) == 0 534 return 535 } 536 537 // nullableBool makes a boolean a pointer when we want to distinguish the zero value from no value set. 538 // This is the case when: 539 // - a x-nullable extension says so in the spec 540 // - it is **not** a read-only property 541 // - it is a required property 542 // - it has a default value 543 func nullableBool(schema *spec.Schema, isRequired bool) bool { 544 if nullable := nullableExtension(schema.Extensions); nullable != nil { 545 return *nullable 546 } 547 required := isRequired && schema.Default == nil && !schema.ReadOnly 548 optional := !isRequired && (schema.Default != nil || schema.ReadOnly) 549 550 return required || optional 551 } 552 553 // nullableNumber makes a number a pointer when we want to distinguish the zero value from no value set. 554 // This is the case when: 555 // - a x-nullable extension says so in the spec 556 // - it is **not** a read-only property 557 // - it is a required property 558 // - boundaries defines the zero value as a valid value: 559 // - there is a non-exclusive boundary set at the zero value of the type 560 // - the [min,max] range crosses the zero value of the type 561 func nullableNumber(schema *spec.Schema, isRequired bool) bool { 562 if nullable := nullableExtension(schema.Extensions); nullable != nil { 563 return *nullable 564 } 565 hasDefault := schema.Default != nil && !swag.IsZero(schema.Default) 566 567 isMin := schema.Minimum != nil && (*schema.Minimum != 0 || schema.ExclusiveMinimum) 568 bcMin := schema.Minimum != nil && *schema.Minimum == 0 && !schema.ExclusiveMinimum 569 isMax := schema.Minimum == nil && (schema.Maximum != nil && (*schema.Maximum != 0 || schema.ExclusiveMaximum)) 570 bcMax := schema.Maximum != nil && *schema.Maximum == 0 && !schema.ExclusiveMaximum 571 isMinMax := (schema.Minimum != nil && schema.Maximum != nil && *schema.Minimum < *schema.Maximum) 572 bcMinMax := (schema.Minimum != nil && schema.Maximum != nil && (*schema.Minimum < 0 && 0 < *schema.Maximum)) 573 574 nullable := !schema.ReadOnly && (isRequired || (hasDefault && !(isMin || isMax || isMinMax)) || bcMin || bcMax || bcMinMax) 575 return nullable 576 } 577 578 // nullableString makes a string nullable when we want to distinguish the zero value from no value set. 579 // This is the case when: 580 // - a x-nullable extension says so in the spec 581 // - it is **not** a read-only property 582 // - it is a required property 583 // - it has a MinLength property set to 0 584 // - it has a default other than "" (the zero for strings) and no MinLength or zero MinLength 585 func nullableString(schema *spec.Schema, isRequired bool) bool { 586 if nullable := nullableExtension(schema.Extensions); nullable != nil { 587 return *nullable 588 } 589 hasDefault := schema.Default != nil && !swag.IsZero(schema.Default) 590 591 isMin := schema.MinLength != nil && *schema.MinLength != 0 592 bcMin := schema.MinLength != nil && *schema.MinLength == 0 593 594 nullable := !schema.ReadOnly && (isRequired || (hasDefault && !isMin) || bcMin) 595 return nullable 596 } 597 598 func nullableStrfmt(schema *spec.Schema, isRequired bool) bool { 599 notBinary := schema.Format != binary 600 if nullable := nullableExtension(schema.Extensions); nullable != nil && notBinary { 601 return *nullable 602 } 603 hasDefault := schema.Default != nil && !swag.IsZero(schema.Default) 604 605 nullable := !schema.ReadOnly && (isRequired || hasDefault) 606 return notBinary && nullable 607 } 608 609 func nullableExtension(ext spec.Extensions) *bool { 610 if ext == nil { 611 return nil 612 } 613 614 if boolPtr := boolExtension(ext, xNullable); boolPtr != nil { 615 return boolPtr 616 } 617 618 return boolExtension(ext, xIsNullable) 619 } 620 621 func boolExtension(ext spec.Extensions, key string) *bool { 622 if v, ok := ext[key]; ok { 623 if bb, ok := v.(bool); ok { 624 return &bb 625 } 626 } 627 return nil 628 } 629 630 func (t *typeResolver) ResolveSchema(schema *spec.Schema, isAnonymous, isRequired bool) (result resolvedType, err error) { 631 debugLog("resolving schema (anon: %t, req: %t) %s", isAnonymous, isRequired, t.ModelName) 632 if schema == nil { 633 result.IsInterface = true 634 result.GoType = iface 635 return 636 } 637 638 tpe := t.firstType(schema) 639 defer setIsEmptyOmitted(&result, schema, tpe) 640 641 var returns bool 642 returns, result, err = t.resolveSchemaRef(schema, isRequired) 643 if returns { 644 if !isAnonymous { 645 result.IsMap = false 646 result.IsComplexObject = true 647 debugLog("not anonymous ref") 648 } 649 debugLog("returning after ref") 650 return 651 } 652 653 // special case of swagger type "file", rendered as io.ReadCloser interface 654 if t.firstType(schema) == file { 655 result.SwaggerType = file 656 result.IsPrimitive = true 657 result.IsNullable = false 658 result.GoType = formatMapping[str][binary] 659 result.IsStream = true 660 return 661 } 662 663 returns, result, err = t.resolveFormat(schema, isAnonymous, isRequired) 664 if returns { 665 debugLog("returning after resolve format: %s", pretty.Sprint(result)) 666 return 667 } 668 669 result.IsNullable = t.isNullable(schema) || isRequired 670 671 switch tpe { 672 case array: 673 result, err = t.resolveArray(schema, isAnonymous, false) 674 return 675 676 case file, number, integer, boolean: 677 result.Extensions = schema.Extensions 678 result.GoType = typeMapping[tpe] 679 result.SwaggerType = tpe 680 t.inferAliasing(&result, schema, isAnonymous, isRequired) 681 682 switch tpe { 683 case boolean: 684 result.IsPrimitive = true 685 result.IsCustomFormatter = false 686 result.IsNullable = nullableBool(schema, isRequired) 687 case number, integer: 688 result.IsPrimitive = true 689 result.IsCustomFormatter = false 690 result.IsNullable = nullableNumber(schema, isRequired) 691 case file: 692 } 693 return 694 695 case str: 696 result.GoType = str 697 result.SwaggerType = str 698 t.inferAliasing(&result, schema, isAnonymous, isRequired) 699 700 result.IsPrimitive = true 701 result.IsNullable = nullableString(schema, isRequired) 702 result.Extensions = schema.Extensions 703 704 case object: 705 result, err = t.resolveObject(schema, isAnonymous) 706 if err != nil { 707 return resolvedType{}, err 708 } 709 result.HasDiscriminator = schema.Discriminator != "" 710 return 711 712 case "null": 713 result.GoType = iface 714 result.SwaggerType = object 715 result.IsNullable = false 716 result.IsInterface = true 717 return 718 719 default: 720 err = fmt.Errorf("unresolvable: %v (format %q)", schema.Type, schema.Format) 721 return 722 } 723 return result, err 724 } 725 726 // resolvedType is a swagger type that has been resolved and analyzed for usage 727 // in a template 728 type resolvedType struct { 729 IsAnonymous bool 730 IsArray bool 731 IsMap bool 732 IsInterface bool 733 IsPrimitive bool 734 IsCustomFormatter bool 735 IsAliased bool 736 IsNullable bool 737 IsStream bool 738 IsEmptyOmitted bool 739 740 // A tuple gets rendered as an anonymous struct with P{index} as property name 741 IsTuple bool 742 HasAdditionalItems bool 743 744 // A complex object gets rendered as a struct 745 IsComplexObject bool 746 747 // A polymorphic type 748 IsBaseType bool 749 HasDiscriminator bool 750 751 GoType string 752 Pkg string 753 PkgAlias string 754 AliasedType string 755 SwaggerType string 756 SwaggerFormat string 757 Extensions spec.Extensions 758 759 // The type of the element in a slice or map 760 ElemType *resolvedType 761 762 // IsMapNullOverride indicates that a nullable object is used within an 763 // aliased map. In this case, the reference is not rendered with a pointer 764 IsMapNullOverride bool 765 766 // IsSuperAlias indicates that the aliased type is really the same type, 767 // e.g. in golang, this translates to: type A = B 768 IsSuperAlias bool 769 } 770 771 func (rt *resolvedType) Zero() string { 772 // if type is aliased, provide zero from the aliased type 773 if rt.IsAliased { 774 if zr, ok := zeroes[rt.AliasedType]; ok { 775 return rt.GoType + "(" + zr + ")" 776 } 777 } 778 // zero function provided as native or by strfmt function 779 if zr, ok := zeroes[rt.GoType]; ok { 780 return zr 781 } 782 // map and slice initializer 783 if rt.IsMap { 784 return "make(" + rt.GoType + ", 50)" 785 } else if rt.IsArray { 786 return "make(" + rt.GoType + ", 0, 50)" 787 } 788 // object initializer 789 if rt.IsTuple || rt.IsComplexObject { 790 if rt.IsNullable { 791 return "new(" + rt.GoType + ")" 792 } 793 return rt.GoType + "{}" 794 } 795 // interface initializer 796 if rt.IsInterface { 797 return "nil" 798 } 799 800 return "" 801 }