@@ -9,8 +9,10 @@ import (
99 "strconv"
1010 "strings"
1111
12+ "google.golang.org/protobuf/reflect/protoreflect"
1213 "github.com/protocolbuffers/txtpbfmt/ast"
1314 "github.com/protocolbuffers/txtpbfmt/config"
15+ "github.com/protocolbuffers/txtpbfmt/descriptor"
1416 "github.com/protocolbuffers/txtpbfmt/quote"
1517 "github.com/protocolbuffers/txtpbfmt/sort"
1618 "github.com/protocolbuffers/txtpbfmt/wrap"
@@ -148,13 +150,33 @@ func ParseWithMetaCommentConfig(in []byte, c config.Config) ([]*ast.Node, error)
148150 if err != nil {
149151 return nil , err
150152 }
153+
154+ // Load descriptor if field number sorting is enabled
155+ var rootDesc protoreflect.MessageDescriptor
156+ if c .SortFieldsByFieldNumber {
157+ if c .ProtoDescriptor == "" {
158+ return nil , fmt .Errorf ("proto_descriptor is required when using sort_fields_by_field_number" )
159+ }
160+
161+ loader , err := descriptor .NewLoader (c .ProtoDescriptor )
162+ if err != nil {
163+ return nil , fmt .Errorf ("failed to create descriptor loader: %v" , err )
164+ }
165+
166+ // Get root message descriptor
167+ rootDesc , err = loader .GetRootMessageDescriptor (c .MessageFullName )
168+ if err != nil {
169+ return nil , fmt .Errorf ("failed to get root message descriptor: %v" , err )
170+ }
171+ }
172+
151173 if p .config .InfoLevel () {
152174 p .config .Infof ("p.in: %q" , string (p .in ))
153175 p .config .Infof ("p.length: %v" , p .length )
154176 }
155177 // Although unnamed nodes aren't strictly allowed, some formats represent a
156178 // list of protos as a list of unnamed top-level nodes.
157- nodes , _ , err := p .parse ( /*isRoot=*/ true )
179+ nodes , _ , err := p .parse ( /*isRoot=*/ true , rootDesc )
158180 if err != nil {
159181 return nil , err
160182 }
@@ -288,6 +310,35 @@ func newParser(in []byte, c config.Config) (*parser, error) {
288310 return parser , nil
289311}
290312
313+ // getFieldNumber returns the field number for a given field name in the descriptor.
314+ func getFieldNumber (desc protoreflect.MessageDescriptor , fieldName string ) int32 {
315+ if desc == nil {
316+ return 0
317+ }
318+
319+ field := desc .Fields ().ByTextName (fieldName )
320+ if field == nil {
321+ return 0
322+ }
323+ return int32 (field .Number ())
324+ }
325+
326+ // findChildDescriptor finds the descriptor for a nested message field.
327+ func (p * parser ) findChildDescriptor (desc protoreflect.MessageDescriptor , fieldName string ) protoreflect.MessageDescriptor {
328+ if desc == nil {
329+ return nil
330+ }
331+
332+ field := desc .Fields ().ByTextName (fieldName )
333+ if field == nil {
334+ return nil
335+ }
336+ if field .Kind () == protoreflect .MessageKind {
337+ return field .Message ()
338+ }
339+ return nil
340+ }
341+
291342func (p * parser ) nextInputIs (b byte ) bool {
292343 return p .index < p .length && p .in [p .index ] == b
293344}
@@ -398,7 +449,7 @@ func (p *parser) consumeOptionalSeparator() error {
398449// format (sequence of messages, each of which passes proto.UnmarshalText()).
399450// endPos is the position of the first character on the first line
400451// after parsed nodes: that's the position to append more children.
401- func (p * parser ) parse (isRoot bool ) (result []* ast.Node , endPos ast.Position , err error ) {
452+ func (p * parser ) parse (isRoot bool , desc protoreflect. MessageDescriptor ) (result []* ast.Node , endPos ast.Position , err error ) {
402453 var res []* ast.Node
403454 res = []* ast.Node {} // empty children is different from nil children
404455 for ld := p .getLoopDetector (); p .index < p .length ; {
@@ -505,14 +556,17 @@ func (p *parser) parse(isRoot bool) (result []*ast.Node, endPos ast.Position, er
505556 return nil , ast.Position {}, err
506557 }
507558
559+ // Set field number from descriptor if available
560+ nd .FieldNumber = getFieldNumber (desc , nd .Name )
561+
508562 // Skip separator.
509563 preCommentsBeforeColon , _ := p .skipWhiteSpaceAndReadComments (true /* multiLine */ )
510564 nd .SkipColon = ! p .consume (':' )
511565 previousPos := p .position ()
512566 preCommentsAfterColon , _ := p .skipWhiteSpaceAndReadComments (true /* multiLine */ )
513567
514568 if p .consume ('{' ) || p .consume ('<' ) {
515- if err := p .parseMessage (nd ); err != nil {
569+ if err := p .parseMessage (nd , desc ); err != nil {
516570 return nil , ast.Position {}, err
517571 }
518572 } else if p .consume ('[' ) {
@@ -562,14 +616,15 @@ func (p *parser) parseFieldName(nd *ast.Node, isRoot bool) error {
562616 return nil
563617}
564618
565- func (p * parser ) parseMessage (nd * ast.Node ) error {
619+ func (p * parser ) parseMessage (nd * ast.Node , desc protoreflect. MessageDescriptor ) error {
566620 if p .config .SkipAllColons {
567621 nd .SkipColon = true
568622 }
569623 nd .ChildrenSameLine = p .bracketSameLine [p .index - 1 ]
570624 nd .IsAngleBracket = p .config .PreserveAngleBrackets && p .in [p .index - 1 ] == '<'
571625 // Recursive call to parse child nodes.
572- nodes , lastPos , err := p .parse ( /*isRoot=*/ false )
626+ childDesc := p .findChildDescriptor (desc , nd .Name )
627+ nodes , lastPos , err := p .parse ( /*isRoot=*/ false , childDesc )
573628 if err != nil {
574629 return err
575630 }
@@ -595,7 +650,7 @@ func (p *parser) parseList(nd *ast.Node, preCommentsBeforeColon, preCommentsAfte
595650 // Handle list of nodes.
596651 nd .ChildrenAsList = true
597652
598- nodes , lastPos , err := p .parse ( /*isRoot=*/ true )
653+ nodes , lastPos , err := p .parse ( /*isRoot=*/ true , nil )
599654 if err != nil {
600655 return err
601656 }
0 commit comments