protoc-gen-ts/internal/protowalk/walk.go

129 lines
2.8 KiB
Go

package protowalk
import (
"google.golang.org/protobuf/reflect/protoreflect"
)
type WalkFunc func(desc protoreflect.Descriptor) bool
func WalkFiles(files []protoreflect.FileDescriptor, f WalkFunc) {
var w walker
w.walkFiles(files, f)
}
type walker struct {
seen map[string]struct{}
}
func (w *walker) enter(name string) bool {
if _, ok := w.seen[name]; ok {
return false
}
if w.seen == nil {
w.seen = make(map[string]struct{})
}
w.seen[name] = struct{}{}
return true
}
func (w *walker) walkFiles(files []protoreflect.FileDescriptor, f WalkFunc) {
for _, file := range files {
w.walkFile(file, f)
}
}
func (w *walker) walkFile(file protoreflect.FileDescriptor, f WalkFunc) {
if w.enter(file.Path()) {
if !f(file) {
return
}
w.walkEnums(file.Enums(), f)
w.walkMessages(file.Messages(), f)
w.walkServices(file.Services(), f)
}
}
func (w *walker) walkEnums(enums protoreflect.EnumDescriptors, f WalkFunc) {
for i := 0; i < enums.Len(); i++ {
w.walkEnum(enums.Get(i), f)
}
}
func (w *walker) walkEnum(enum protoreflect.EnumDescriptor, f WalkFunc) {
if w.enter(string(enum.FullName())) {
f(enum)
}
}
func (w *walker) walkMessages(messages protoreflect.MessageDescriptors, f WalkFunc) {
for i := 0; i < messages.Len(); i++ {
w.walkMessage(messages.Get(i), f)
}
}
func (w *walker) walkMessage(message protoreflect.MessageDescriptor, f WalkFunc) {
if w.enter(string(message.FullName())) {
if !f(message) {
return
}
w.walkFields(message.Fields(), f)
w.walkMessages(message.Messages(), f)
w.walkEnums(message.Enums(), f)
}
}
func (w *walker) walkFields(fields protoreflect.FieldDescriptors, f WalkFunc) {
for i := 0; i < fields.Len(); i++ {
w.walkField(fields.Get(i), f)
}
}
func (w *walker) walkField(field protoreflect.FieldDescriptor, f WalkFunc) {
if w.enter(string(field.FullName())) {
if !f(field) {
return
}
if field.IsMap() {
w.walkField(field.MapKey(), f)
w.walkField(field.MapValue(), f)
}
if field.Message() != nil {
w.walkMessage(field.Message(), f)
}
if field.Enum() != nil {
w.walkEnum(field.Enum(), f)
}
}
}
func (w *walker) walkServices(services protoreflect.ServiceDescriptors, f WalkFunc) {
for i := 0; i < services.Len(); i++ {
w.walkService(services.Get(i), f)
}
}
func (w *walker) walkService(service protoreflect.ServiceDescriptor, f WalkFunc) {
if w.enter(string(service.FullName())) {
if !f(service) {
return
}
w.walkMethods(service.Methods(), f)
}
}
func (w *walker) walkMethods(methods protoreflect.MethodDescriptors, f WalkFunc) {
for i := 0; i < methods.Len(); i++ {
w.walkMethod(methods.Get(i), f)
}
}
func (w *walker) walkMethod(method protoreflect.MethodDescriptor, f WalkFunc) {
if w.enter(string(method.FullName())) {
if !f(method) {
return
}
w.walkMessage(method.Input(), f)
w.walkMessage(method.Output(), f)
}
}