func (p *plugin) hasLoop(field *descriptor.FieldDescriptorProto, visited []*generator.Descriptor, excludes []*generator.Descriptor) *generator.Descriptor { if field.IsMessage() || p.IsGroup(field) || p.IsMap(field) { var fieldMessage *generator.Descriptor if p.IsMap(field) { m := p.GoMapType(nil, field) if !m.ValueField.IsMessage() { return nil } fieldMessage = p.ObjectNamed(m.ValueField.GetTypeName()).(*generator.Descriptor) } else { fieldMessage = p.ObjectNamed(field.GetTypeName()).(*generator.Descriptor) } fieldTypeName := generator.CamelCaseSlice(fieldMessage.TypeName()) for _, message := range visited { messageTypeName := generator.CamelCaseSlice(message.TypeName()) if fieldTypeName == messageTypeName { for _, e := range excludes { if fieldTypeName == generator.CamelCaseSlice(e.TypeName()) { return nil } } return fieldMessage } } for _, f := range fieldMessage.Field { visited = append(visited, fieldMessage) loopTo := p.hasLoop(f, visited, excludes) if loopTo != nil { return loopTo } } } return nil }
func (p *plugin) checkNameSpace(message *generator.Descriptor) map[string]bool { ccTypeName := generator.CamelCaseSlice(message.TypeName()) names := make(map[string]bool) for _, field := range message.Field { fieldname := generator.CamelCase(*field.Name) if field.IsMessage() && gogoproto.IsEmbed(field) { desc := p.ObjectNamed(field.GetTypeName()) moreNames := p.checkNameSpace(desc.(*generator.Descriptor)) for another := range moreNames { if names[another] { fmt.Fprintf(os.Stderr, "ERROR: duplicate embedded fieldname %v in type %v\n", fieldname, ccTypeName) os.Exit(1) } names[another] = true } } else { if names[fieldname] { fmt.Fprintf(os.Stderr, "ERROR: duplicate embedded fieldname %v in type %v\n", fieldname, ccTypeName) os.Exit(1) } names[fieldname] = true } } return names }
func (g *jsonschema) generateMessageSchema(file *generator.FileDescriptor, msg *generator.Descriptor, index int) { typeName := file.GetPackage() + "." + strings.Join(msg.TypeName(), ".") typeName = strings.TrimPrefix(typeName, ".") if g.definitions[typeName] == nil { def, deps := g.messageToSchema(file, msg) g.definitions[typeName] = def g.dependencies[typeName] = deps } }
func (p *plugin) checkRepeated(message *generator.Descriptor) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) for _, field := range message.Field { if !gogoproto.IsEmbed(field) { continue } if field.IsBytes() { fieldname := generator.CamelCase(*field.Name) fmt.Fprintf(os.Stderr, "ERROR: found embedded bytes field %s in message %s\n", fieldname, ccTypeName) os.Exit(1) } if !field.IsRepeated() { continue } fieldname := generator.CamelCase(*field.Name) fmt.Fprintf(os.Stderr, "ERROR: found repeated embedded field %s in message %s\n", fieldname, ccTypeName) os.Exit(1) } }
func (p *plugin) checkOverwrite(message *generator.Descriptor, enablers map[string]gogoproto.EnableFunc) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) names := []string{} for name := range enablers { names = append(names, name) } for _, field := range message.Field { if field.IsMessage() && gogoproto.IsEmbed(field) { fieldname := generator.CamelCase(*field.Name) desc := p.ObjectNamed(field.GetTypeName()) msg := desc.(*generator.Descriptor) for errStr, enabled := range enablers { if enabled(msg.File(), msg.DescriptorProto) { fmt.Fprintf(os.Stderr, "WARNING: found non-%v %v with embedded %v %v\n", names, ccTypeName, errStr, fieldname) } } p.checkOverwrite(msg, enablers) } } }
func (g *jsonschema) messageToSchema(file *generator.FileDescriptor, desc *generator.Descriptor) (interface{}, []string) { typeName := file.GetPackage() + "." + strings.Join(desc.TypeName(), ".") typeName = strings.TrimPrefix(typeName, ".") title := desc.TypeName()[len(desc.TypeName())-1] var ( dependencies []string properties = make(map[string]interface{}) requiredProperties []string ) for i, field := range desc.GetField() { if field.OneofIndex != nil { continue } f, dep := g.fieldToSchema(field) if f == nil { continue } if limbo.IsRequiredProperty(field) { requiredProperties = append(requiredProperties, getJSONName(field)) } { comment := g.gen.Comments(fmt.Sprintf("%s,%d,%d", desc.Path(), 2, i)) comment = strings.TrimSpace(comment) if comment != "" { f["description"] = comment } } properties[getJSONName(field)] = f if dep != "" { dependencies = append(dependencies, dep) } } schema := map[string]interface{}{ "type": "object", "properties": properties, } if len(requiredProperties) > 0 { schema["required"] = requiredProperties } if len(desc.OneofDecl) > 0 { allOffDefs := make([]interface{}, 0, 1+len(desc.OneofDecl)) oneOfDefs := make([][]interface{}, len(desc.OneofDecl)) for i, field := range desc.GetField() { if field.OneofIndex == nil { continue } oneofIndex := *field.OneofIndex f, dep := g.fieldToSchema(field) if f == nil { continue } if field.IsRepeated() { f = map[string]interface{}{ "type": "array", "items": f, } } { comment := g.gen.Comments(fmt.Sprintf("%s,%d,%d", desc.Path(), 2, i)) comment = strings.TrimSpace(comment) if comment != "" { f["description"] = comment } } def := map[string]interface{}{ "type": "object", "properties": map[string]interface{}{ getJSONName(field): f, }, "required": []string{getJSONName(field)}, } oneOfDefs[oneofIndex] = append(oneOfDefs[oneofIndex], def) if dep != "" { dependencies = append(dependencies, dep) } } allOffDefs = append(allOffDefs, schema) for i, defs := range oneOfDefs { def := map[string]interface{}{ "oneOf": defs, } { comment := g.gen.Comments(fmt.Sprintf("%s,%d,%d", desc.Path(), 8, i)) comment = strings.TrimSpace(comment) if comment != "" { def["description"] = comment } } allOffDefs = append(allOffDefs, def) } schema = map[string]interface{}{ "type": "object", "allOf": allOffDefs, } } { comment := g.gen.Comments(desc.Path()) comment = strings.TrimSpace(comment) if comment != "" { schema["description"] = comment } } { schema["title"] = title // schema["id"] = typeName } { dependencies = uniqStrings(dependencies) } return schema, dependencies }
func (p *plugin) generateMessage(file *generator.FileDescriptor, message *generator.Descriptor) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) p.P(`func (this *`, ccTypeName, `) Compare(that interface{}) int {`) p.In() p.generateMsgNullAndTypeCheck(ccTypeName) oneofs := make(map[string]struct{}) for _, field := range message.Field { oneof := field.OneofIndex != nil if oneof { fieldname := p.GetFieldName(message, field) if _, ok := oneofs[fieldname]; ok { continue } else { oneofs[fieldname] = struct{}{} } p.P(`if that1.`, fieldname, ` == nil {`) p.In() p.P(`if this.`, fieldname, ` != nil {`) p.In() p.P(`return 1`) p.Out() p.P(`}`) p.Out() p.P(`} else if this.`, fieldname, ` == nil {`) p.In() p.P(`return -1`) p.Out() p.P(`} else if c := this.`, fieldname, `.Compare(that1.`, fieldname, `); c != 0 {`) p.In() p.P(`return c`) p.Out() p.P(`}`) } else { p.generateField(file, message, field) } } if message.DescriptorProto.HasExtension() { fieldname := "XXX_extensions" if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) { p.P(`extkeys := make([]int32, 0, len(this.`, fieldname, `)+len(that1.`, fieldname, `))`) p.P(`for k, _ := range this.`, fieldname, ` {`) p.In() p.P(`extkeys = append(extkeys, k)`) p.Out() p.P(`}`) p.P(`for k, _ := range that1.`, fieldname, ` {`) p.In() p.P(`if _, ok := this.`, fieldname, `[k]; !ok {`) p.In() p.P(`extkeys = append(extkeys, k)`) p.Out() p.P(`}`) p.Out() p.P(`}`) p.P(p.sortkeysPkg.Use(), `.Int32s(extkeys)`) p.P(`for _, k := range extkeys {`) p.In() p.P(`if v, ok := this.`, fieldname, `[k]; ok {`) p.In() p.P(`if v2, ok := that1.`, fieldname, `[k]; ok {`) p.In() p.P(`if c := v.Compare(&v2); c != 0 {`) p.In() p.P(`return c`) p.Out() p.P(`}`) p.Out() p.P(`} else {`) p.In() p.P(`return 1`) p.Out() p.P(`}`) p.Out() p.P(`} else {`) p.In() p.P(`return -1`) p.Out() p.P(`}`) p.Out() p.P(`}`) } else { p.P(`if c := `, p.bytesPkg.Use(), `.Compare(this.`, fieldname, `, that1.`, fieldname, `); c != 0 {`) p.In() p.P(`return c`) p.Out() p.P(`}`) } } if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) { fieldname := "XXX_unrecognized" p.P(`if c := `, p.bytesPkg.Use(), `.Compare(this.`, fieldname, `, that1.`, fieldname, `); c != 0 {`) p.In() p.P(`return c`) p.Out() p.P(`}`) } p.P(`return 0`) p.Out() p.P(`}`) //Generate Compare methods for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, field := range m.Field { oneof := field.OneofIndex != nil if !oneof { continue } ccTypeName := p.OneOfTypeName(message, field) p.P(`func (this *`, ccTypeName, `) Compare(that interface{}) int {`) p.In() p.generateMsgNullAndTypeCheck(ccTypeName) vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(field) p.generateField(file, message, field) p.P(`return 0`) p.Out() p.P(`}`) } }
func (p *plugin) generateMessage(file *generator.FileDescriptor, message *generator.Descriptor, verbose bool) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) if verbose { p.P(`func (this *`, ccTypeName, `) VerboseEqual(that interface{}) error {`) } else { p.P(`func (this *`, ccTypeName, `) Equal(that interface{}) bool {`) } p.In() p.generateMsgNullAndTypeCheck(ccTypeName, verbose) oneofs := make(map[string]struct{}) for _, field := range message.Field { oneof := field.OneofIndex != nil if oneof { fieldname := p.GetFieldName(message, field) if _, ok := oneofs[fieldname]; ok { continue } else { oneofs[fieldname] = struct{}{} } p.P(`if that1.`, fieldname, ` == nil {`) p.In() p.P(`if this.`, fieldname, ` != nil {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` != nil && that1.`, fieldname, ` == nil")`) } else { p.P(`return false`) } p.Out() p.P(`}`) p.Out() p.P(`} else if this.`, fieldname, ` == nil {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` == nil && that1.`, fieldname, ` != nil")`) } else { p.P(`return false`) } p.Out() if verbose { p.P(`} else if err := this.`, fieldname, `.VerboseEqual(that1.`, fieldname, `); err != nil {`) } else { p.P(`} else if !this.`, fieldname, `.Equal(that1.`, fieldname, `) {`) } p.In() if verbose { p.P(`return err`) } else { p.P(`return false`) } p.Out() p.P(`}`) } else { p.generateField(file, message, field, verbose) } } if message.DescriptorProto.HasExtension() { fieldname := "XXX_extensions" if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) { p.P(`for k, v := range this.`, fieldname, ` {`) p.In() p.P(`if v2, ok := that1.`, fieldname, `[k]; ok {`) p.In() p.P(`if !v.Equal(&v2) {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this[%v](%v) Not Equal that[%v](%v)", k, this.`, fieldname, `[k], k, that1.`, fieldname, `[k])`) } else { p.P(`return false`) } p.Out() p.P(`}`) p.Out() p.P(`} else {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, `[%v] Not In that", k)`) } else { p.P(`return false`) } p.Out() p.P(`}`) p.Out() p.P(`}`) p.P(`for k, _ := range that1.`, fieldname, ` {`) p.In() p.P(`if _, ok := this.`, fieldname, `[k]; !ok {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, `[%v] Not In this", k)`) } else { p.P(`return false`) } p.Out() p.P(`}`) p.Out() p.P(`}`) } else { p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`) } else { p.P(`return false`) } p.Out() p.P(`}`) } } if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) { fieldname := "XXX_unrecognized" p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`) } else { p.P(`return false`) } p.Out() p.P(`}`) } if verbose { p.P(`return nil`) } else { p.P(`return true`) } p.Out() p.P(`}`) //Generate Equal methods for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, field := range m.Field { oneof := field.OneofIndex != nil if !oneof { continue } ccTypeName := p.OneOfTypeName(message, field) if verbose { p.P(`func (this *`, ccTypeName, `) VerboseEqual(that interface{}) error {`) } else { p.P(`func (this *`, ccTypeName, `) Equal(that interface{}) bool {`) } p.In() p.generateMsgNullAndTypeCheck(ccTypeName, verbose) vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(field) p.generateField(file, message, field, verbose) if verbose { p.P(`return nil`) } else { p.P(`return true`) } p.Out() p.P(`}`) } }