Skip to content

Add FieldDescriptor, EnumValueDescriptor, OneofDescriptor, and comment access#14

Merged
cocoahero merged 6 commits into
mainfrom
feature/field-descriptor
Jul 7, 2026
Merged

Add FieldDescriptor, EnumValueDescriptor, OneofDescriptor, and comment access#14
cocoahero merged 6 commits into
mainfrom
feature/field-descriptor

Conversation

@cocoahero

@cocoahero cocoahero commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

Fills out the descriptor-wrapper layer so plugins can work with the parts of a generation request that previously required dropping down to the raw google-protobuf API — most importantly fields, plus enum values, oneofs, and comments.

What's new

  • FieldDescriptor (MessageDescriptor#fields) — wraps FieldDescriptorProto with:
    • #type_descriptor — resolves message/enum fields to their MessageDescriptor/EnumDescriptor via the context (nil for scalars / types not in the request)
    • type predicates: #message?, #enum?, #group?, #scalar?
    • cardinality: #repeated?, #required?, #optional?, #proto3_optional?
    • oneof correlation: #oneof?, #oneof (proto3 synthetic optionals excluded)
  • EnumValueDescriptor (EnumDescriptor#values) — #name, #number, #full_name.
  • OneofDescriptor (MessageDescriptor#oneofs) — #name, #index, #fields (its member fields).
  • Comments via a Commentable mixin on every wrapper — #leading_comments, #trailing_comments, #comments, #source_location.

How comments work

Comments live in FileDescriptorProto.source_code_info, keyed by a numeric path into the descriptor tree, not on the descriptors. FileDescriptor walks that tree once and builds an identity-keyed map from each raw descriptor proto to its SourceCodeInfo::Location; wrappers reach their file via a uniform #file accessor and look themselves up. Empty comments normalize to nil.

Detached comments are intentionally not exposed: per protoc they appear before "but [are] not connected to" the element (the author separated them with a blank line), so they are file organization (section headers/notes) rather than documentation of any element.

Notes / minor breaking changes

Internal constructor signatures gained a context argument (MessageDescriptor.new(descriptor, parent, context)). These wrappers are constructed internally, not part of the documented plugin API, but flagging it since this is pre-1.0.

Testing

  • New tests for each wrapper and for comment resolution across all descriptor types.
  • Blog fixtures extended (a CommentEvent message with a oneof, plus comments) and regenerated via bin/fixtures.
  • bin/rake (test + rubocop): 69 runs, 172 assertions, 0 failures, rubocop clean.

cocoahero added 6 commits July 7, 2026 14:48
Introduce a FieldDescriptor wrapper around FieldDescriptorProto with
type-resolution (#type_descriptor via the context), type predicates
(#message?/#enum?/#group?/#scalar?), and cardinality helpers
(#repeated?/#required?/#optional?/#proto3_optional?).

MessageDescriptor now exposes #fields and threads the Context through
its initializer so fields can resolve their referenced types.
Introduce EnumValueDescriptor (name/number/#full_name) exposed via
EnumDescriptor#values, and OneofDescriptor (#name/#index/#fields)
exposed via MessageDescriptor#oneofs.

FieldDescriptor gains #oneof? and #oneof to correlate a field with its
containing oneof, excluding proto3 synthetic optional oneofs.

Add a CommentEvent message with a oneof to the blog fixtures (and
regenerate blog.cgr/blog.fds) to exercise oneof handling.
Add a Commentable mixin exposing #leading_comments, #trailing_comments,
and #leading_detached_comments on every descriptor wrapper (file,
message, field, enum, enum value, oneof, service, method).

FileDescriptor builds an identity-keyed index from each raw descriptor
proto to its SourceCodeInfo::Location by reconstructing the numeric
paths protoc emits; wrappers reach their file via a uniform #file
accessor. Empty comments normalize to nil.

Add comments to the blog fixtures (and regenerate) to exercise comment
resolution for each descriptor type.
Returns detached blocks, the leading comment, and the trailing comment
as a single array in source order, omitting empties.
Per protoc, leading_detached_comments appear before but are "not
connected to" the element (separated by a blank line), so they are
section headers or notes rather than documentation of the element.
#comments now returns only the attached leading and trailing comments;
detached blocks remain available via #leading_detached_comments.

Add a detached comment to the fixtures to cover the distinction.
Detached comments are proto file organization (section headers, notes)
rather than documentation attached to any element, and their placement
is awkward to reason about. Remove the accessor and the fixture that
exercised it; #comments already surfaces only attached leading/trailing
comments.
@cocoahero cocoahero merged commit 2d56791 into main Jul 7, 2026
5 checks passed
@cocoahero cocoahero deleted the feature/field-descriptor branch July 7, 2026 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant