func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema, knowns map[string]struct{}) []dupProp { var dups []dupProp schn := nm schc := &sch for schc.Ref.String() != "" { // gather property names reso, err := spec.ResolveRef(s.spec.Spec(), &schc.Ref) if err != nil { panic(err) } schc = reso schn = sch.Ref.String() } if len(schc.AllOf) > 0 { for _, chld := range schc.AllOf { dups = append(dups, s.validateSchemaPropertyNames(schn, chld, knowns)...) } return dups } for k := range schc.Properties { _, ok := knowns[k] if ok { dups = append(dups, dupProp{Name: k, Definition: schn}) } else { knowns[k] = struct{}{} } } return dups }
func (s *SpecValidator) validateCircularAncestry(nm string, sch spec.Schema, knowns map[string]struct{}) []string { if sch.Ref.String() == "" && len(sch.AllOf) == 0 { return nil } var ancs []string schn := nm schc := &sch for schc.Ref.String() != "" { reso, err := spec.ResolveRef(s.spec.Spec(), &schc.Ref) if err != nil { panic(err) } schc = reso schn = sch.Ref.String() } if schn != nm && schn != "" { if _, ok := knowns[schn]; ok { ancs = append(ancs, schn) } knowns[schn] = struct{}{} if len(ancs) > 0 { return ancs } } if len(schc.AllOf) > 0 { for _, chld := range schc.AllOf { if chld.Ref.String() != "" || len(chld.AllOf) > 0 { ancs = append(ancs, s.validateCircularAncestry(schn, chld, knowns)...) if len(ancs) > 0 { return ancs } } } } return ancs }
func (t *typeResolver) resolveSchemaRef(schema *spec.Schema, isRequired bool) (returns bool, result resolvedType, err error) { if schema.Ref.String() != "" { if Debug { _, file, pos, _ := runtime.Caller(1) log.Printf("%s:%d: resolving ref (anon: %t, req: %t) %s\n", filepath.Base(file), pos, false, isRequired, schema.Ref.String()) } returns = true ref, er := spec.ResolveRef(t.Doc.Spec(), &schema.Ref) if er != nil { err = er return } var nm = filepath.Base(schema.Ref.GetURL().Fragment) var tn string if gn, ok := ref.Extensions["x-go-name"]; ok { tn = gn.(string) nm = tn } /*else { tn = swag.ToGoName(nm) }*/ res, er := t.ResolveSchema(ref, false, isRequired) if er != nil { err = er return } result = res result.GoType = t.goTypeName(nm) result.HasDiscriminator = ref.Discriminator != "" result.IsNullable = t.IsNullable(ref) //result.IsAliased = true return } return }
func (s *SpecValidator) resolveRef(ref *spec.Ref) (*spec.Schema, error) { if s.spec.SpecFilePath() != "" { return spec.ResolveRefWithBase(s.spec.Spec(), ref, &spec.ExpandOptions{RelativeBase: s.spec.SpecFilePath()}) } return spec.ResolveRef(s.spec.Spec(), ref) }
func (sg *schemaGenContext) buildProperties() error { if Debug { log.Printf("building properties %s (parent: %s)", sg.Name, sg.Container) } //var discriminatorField string //if sg.Discrimination != nil { //dis, ok := sg.Discriminated["#/definitions/"+sg.Container] //if ok { //} //} for k, v := range sg.Schema.Properties { if Debug { bbb, _ := json.MarshalIndent(sg.Schema, "", " ") log.Printf("building property %s[%q] (tup: %t) %s\n", sg.Name, k, sg.IsTuple, bbb) } // check if this requires de-anonymizing, if so lift this as a new struct and extra schema tpe, err := sg.TypeResolver.ResolveSchema(&v, true, sg.IsTuple || containsString(sg.Schema.Required, k)) if sg.Schema.Discriminator == k { tpe.IsNullable = false } if err != nil { return err } vv := v var hasValidation bool var needsValidation bool if tpe.IsComplexObject && tpe.IsAnonymous && len(v.Properties) > 0 { pg := sg.makeNewStruct(sg.Name+swag.ToGoName(k), v) pg.IsTuple = sg.IsTuple if sg.Path != "" { pg.Path = sg.Path + "+ \".\"+" + fmt.Sprintf("%q", k) } else { pg.Path = fmt.Sprintf("%q", k) } if err := pg.makeGenSchema(); err != nil { return err } if v.Discriminator != "" { pg.GenSchema.IsBaseType = true pg.GenSchema.IsExported = true pg.GenSchema.HasBaseType = true } vv = *spec.RefProperty("#/definitions/" + pg.Name) hasValidation = pg.GenSchema.HasValidations needsValidation = pg.GenSchema.NeedsValidation sg.MergeResult(pg, false) sg.ExtraSchemas[pg.Name] = pg.GenSchema } emprop := sg.NewStructBranch(k, vv) emprop.IsTuple = sg.IsTuple if err := emprop.makeGenSchema(); err != nil { return err } if hasValidation || emprop.GenSchema.HasValidations { emprop.GenSchema.HasValidations = true sg.GenSchema.HasValidations = true } if needsValidation || emprop.GenSchema.NeedsValidation { emprop.GenSchema.NeedsValidation = true sg.GenSchema.NeedsValidation = true } if emprop.Schema.Ref.String() != "" { ref := emprop.Schema.Ref var sch *spec.Schema for ref.String() != "" { rsch, err := spec.ResolveRef(sg.TypeResolver.Doc.Spec(), &ref) if err != nil { return err } ref = rsch.Ref if rsch != nil && rsch.Ref.String() != "" { ref = rsch.Ref continue } ref = spec.Ref{} sch = rsch } if emprop.Discrimination != nil { if _, ok := emprop.Discrimination.Discriminators[emprop.Schema.Ref.String()]; ok { emprop.GenSchema.IsBaseType = true emprop.GenSchema.IsNullable = false emprop.GenSchema.HasBaseType = true } if _, ok := emprop.Discrimination.Discriminated[emprop.Schema.Ref.String()]; ok { emprop.GenSchema.IsSubType = true } } var nm = filepath.Base(emprop.Schema.Ref.GetURL().Fragment) var tn string if gn, ok := emprop.Schema.Extensions["x-go-name"]; ok { tn = gn.(string) nm = tn } else { tn = swag.ToGoName(nm) } tr := newTypeResolver(sg.TypeResolver.ModelsPackage, sg.TypeResolver.Doc) tr.ModelName = tn ttpe, err := tr.ResolveSchema(sch, false, true) if err != nil { return err } if ttpe.IsAliased { emprop.GenSchema.IsAliased = true } nv, hv := hasValidations(sch, false) if hv { emprop.GenSchema.HasValidations = true } if nv { emprop.GenSchema.NeedsValidation = true } } if sg.Schema.Discriminator == k { emprop.GenSchema.IsNullable = false } if emprop.GenSchema.IsBaseType { sg.GenSchema.HasBaseType = true } sg.MergeResult(emprop, false) sg.GenSchema.Properties = append(sg.GenSchema.Properties, emprop.GenSchema) } sort.Sort(sg.GenSchema.Properties) return nil }
func makeGenDefinitionHierarchy(name, pkg, container string, schema spec.Schema, specDoc *loads.Document, includeValidator, includeModel bool) (*GenDefinition, error) { receiver := "m" resolver := newTypeResolver("", specDoc) resolver.ModelName = name analyzed := analysis.New(specDoc.Spec()) di := discriminatorInfo(analyzed) pg := schemaGenContext{ Path: "", Name: name, Receiver: receiver, IndexVar: "i", ValueExpr: receiver, Schema: schema, Required: false, TypeResolver: resolver, Named: true, ExtraSchemas: make(map[string]GenSchema), Discrimination: di, Container: container, IncludeValidator: includeValidator, IncludeModel: includeModel, } if err := pg.makeGenSchema(); err != nil { return nil, err } dsi, ok := di.Discriminators["#/definitions/"+name] if ok { // when these 2 are true then the schema will render as an interface pg.GenSchema.IsBaseType = true pg.GenSchema.IsExported = true pg.GenSchema.DiscriminatorField = dsi.FieldName for _, v := range dsi.Children { if pg.GenSchema.Discriminates == nil { pg.GenSchema.Discriminates = make(map[string]string) } pg.GenSchema.Discriminates[v.FieldValue] = v.GoType } } dse, ok := di.Discriminated["#/definitions/"+name] if ok { pg.GenSchema.DiscriminatorField = dse.FieldName pg.GenSchema.DiscriminatorValue = dse.FieldValue pg.GenSchema.IsSubType = true // find the referenced definitions // check if it has a discriminator defined // when it has a discriminator get the schema and run makeGenSchema for it. // replace the ref with this new genschema swsp := specDoc.Spec() for i, ss := range schema.AllOf { ref := ss.Ref for ref.String() != "" { rsch, err := spec.ResolveRef(swsp, &ref) if err != nil { return nil, err } ref = rsch.Ref if rsch != nil && rsch.Ref.String() != "" { ref = rsch.Ref continue } ref = spec.Ref{} if rsch != nil && rsch.Discriminator != "" { gs, err := makeGenDefinitionHierarchy(strings.TrimPrefix(ss.Ref.String(), "#/definitions/"), pkg, pg.GenSchema.Name, *rsch, specDoc, pg.IncludeValidator, pg.IncludeModel) if err != nil { return nil, err } gs.GenSchema.IsBaseType = true gs.GenSchema.IsExported = true pg.GenSchema.AllOf[i] = gs.GenSchema schPtr := &(pg.GenSchema.AllOf[i]) if schPtr.AdditionalItems != nil { schPtr.AdditionalItems.IsBaseType = true } if schPtr.AdditionalProperties != nil { schPtr.AdditionalProperties.IsBaseType = true } for j := range schPtr.Properties { schPtr.Properties[j].IsBaseType = true schPtr.Properties[j].ValueExpression += "()" } } } } } var defaultImports []string if pg.GenSchema.HasValidations { defaultImports = []string{ "github.com/go-openapi/errors", "github.com/go-openapi/runtime", "github.com/go-openapi/validate", } } var extras []GenSchema var extraKeys []string for k := range pg.ExtraSchemas { extraKeys = append(extraKeys, k) } sort.Strings(extraKeys) for _, k := range extraKeys { extras = append(extras, pg.ExtraSchemas[k]) } return &GenDefinition{ Package: mangleName(filepath.Base(pkg), "definitions"), GenSchema: pg.GenSchema, DependsOn: pg.Dependencies, DefaultImports: defaultImports, ExtraSchemas: extras, }, nil }