generate dartdocs for grpc services (#993)
generate dartdocs for grpc services; fix https://github.com/google/protobuf.dart/issues/973
diff --git a/protoc_plugin/CHANGELOG.md b/protoc_plugin/CHANGELOG.md
index c41f2f0..5c5fe95 100644
--- a/protoc_plugin/CHANGELOG.md
+++ b/protoc_plugin/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 22.1.1-wip
+
+* Generate dartdocs for grpc services ([#973]).
+
+[#973]: https://github.com/google/protobuf.dart/issues/973
+
## 22.1.0
* Fix factory argument types for protobuf `Map` fields. ([#975])
diff --git a/protoc_plugin/lib/src/client_generator.dart b/protoc_plugin/lib/src/client_generator.dart
index cc82735..7112e06 100644
--- a/protoc_plugin/lib/src/client_generator.dart
+++ b/protoc_plugin/lib/src/client_generator.dart
@@ -10,26 +10,28 @@
final String className;
final Set<String> usedMethodNames = {...reservedMemberNames};
- /// Tag of `FileDescriptorProto.service`.
- static const _fileDescriptorServiceTag = 6;
-
/// Tag of `ServiceDescriptorProto.method`.
- static const _serviceDescriptorMethodTag = 2;
+ static const serviceDescriptorMethodTag = 2;
+
+ /// Tag of `FileDescriptorProto.service`.
+ static const fileDescriptorServiceTag = 6;
/// Index of the service in `FileDescriptorProto.service` repeated field.
final int _repeatedFieldIndex;
- List<int> get _serviceDescriptorPath => [
- ...service.fileGen.fieldPath,
- _fileDescriptorServiceTag,
- _repeatedFieldIndex
- ];
+ late final List<int> _serviceDescriptorPath = [
+ ...service.fileGen.fieldPath,
+ fileDescriptorServiceTag,
+ _repeatedFieldIndex
+ ];
- List<int> _methodDescriptorPath(int methodRepeatedFieldIndex) => [
- ..._serviceDescriptorPath,
- _serviceDescriptorMethodTag,
- methodRepeatedFieldIndex
- ];
+ List<int> _methodDescriptorPath(int methodIndex) {
+ return [
+ ..._serviceDescriptorPath,
+ serviceDescriptorMethodTag,
+ methodIndex,
+ ];
+ }
ClientApiGenerator(
this.service, Set<String> usedNames, this._repeatedFieldIndex)
@@ -63,21 +65,22 @@
}
// Subclasses can override this.
- void generateMethod(IndentingWriter out, MethodDescriptorProto m,
- int methodRepeatedFieldIndex) {
+ void generateMethod(
+ IndentingWriter out, MethodDescriptorProto method, int methodIndex) {
final methodName = disambiguateName(
- avoidInitialUnderscore(service._methodName(m.name)),
+ avoidInitialUnderscore(service._methodName(method.name)),
usedMethodNames,
defaultSuffixes());
- final inputType = service._getDartClassName(m.inputType, forMainFile: true);
+ final inputType =
+ service._getDartClassName(method.inputType, forMainFile: true);
final outputType =
- service._getDartClassName(m.outputType, forMainFile: true);
- final commentBlock = service.fileGen
- .commentBlock(_methodDescriptorPath(methodRepeatedFieldIndex));
+ service._getDartClassName(method.outputType, forMainFile: true);
+ final commentBlock =
+ service.fileGen.commentBlock(_methodDescriptorPath(methodIndex));
if (commentBlock != null) {
out.println(commentBlock);
}
- if (m.options.deprecated) {
+ if (method.options.deprecated) {
out.println(
'@$coreImportPrefix.Deprecated(\'This method is deprecated\')');
}
@@ -86,7 +89,7 @@
'$protobufImportPrefix.ClientContext? ctx, $inputType request) =>',
';', () {
out.println('_client.invoke<$outputType>(ctx, \'$className\', '
- '\'${m.name}\', request, $outputType())');
+ '\'${method.name}\', request, $outputType())');
});
}
}
diff --git a/protoc_plugin/lib/src/code_generator.dart b/protoc_plugin/lib/src/code_generator.dart
index 1afec45..dd4c19f 100644
--- a/protoc_plugin/lib/src/code_generator.dart
+++ b/protoc_plugin/lib/src/code_generator.dart
@@ -32,7 +32,7 @@
/// the message in question.
/// For more information see
/// https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/descriptor.proto#L728
- List<int>? get fieldPath;
+ List<int> get fieldPath;
/// The fully qualified name with a leading '.'.
///
diff --git a/protoc_plugin/lib/src/enum_generator.dart b/protoc_plugin/lib/src/enum_generator.dart
index 287a4fe..ea26f34 100644
--- a/protoc_plugin/lib/src/enum_generator.dart
+++ b/protoc_plugin/lib/src/enum_generator.dart
@@ -29,12 +29,10 @@
/// Maps the name of an enum value to the Dart name we will use for it.
final Map<String, String> dartNames = <String, String>{};
final List<int> _originalAliasIndices = <int>[];
- List<int>? _fieldPath;
final List<int> _fieldPathSegment;
@override
- List<int> get fieldPath =>
- _fieldPath ??= List.from(parent.fieldPath!)..addAll(_fieldPathSegment);
+ late final List<int> fieldPath = [...parent.fieldPath, ..._fieldPathSegment];
EnumGenerator._(EnumDescriptorProto descriptor, this.parent,
Set<String> usedClassNames, int repeatedFieldIndex, int fieldIdTag)
diff --git a/protoc_plugin/lib/src/extension_generator.dart b/protoc_plugin/lib/src/extension_generator.dart
index f9eef30..03ace98 100644
--- a/protoc_plugin/lib/src/extension_generator.dart
+++ b/protoc_plugin/lib/src/extension_generator.dart
@@ -16,8 +16,7 @@
final List<int> _fieldPathSegment;
/// See [ProtobufContainer]
- late final List<int> fieldPath = List.from(_parent.fieldPath!)
- ..addAll(_fieldPathSegment);
+ late final List<int> fieldPath = [..._parent.fieldPath, ..._fieldPathSegment];
ExtensionGenerator._(this._descriptor, this._parent, Set<String> usedNames,
int repeatedFieldIndex, int fieldIdTag)
diff --git a/protoc_plugin/lib/src/file_generator.dart b/protoc_plugin/lib/src/file_generator.dart
index 0eb7a35..cb06ca0 100644
--- a/protoc_plugin/lib/src/file_generator.dart
+++ b/protoc_plugin/lib/src/file_generator.dart
@@ -175,7 +175,7 @@
for (var i = 0; i < descriptor.service.length; i++) {
final service = descriptor.service[i];
if (options.useGrpc) {
- grpcGenerators.add(GrpcServiceGenerator(service, this));
+ grpcGenerators.add(GrpcServiceGenerator(service, this, i));
} else {
final serviceGen =
ServiceGenerator(service, this, usedTopLevelServiceNames);
diff --git a/protoc_plugin/lib/src/generated/dart_options.pb.dart b/protoc_plugin/lib/src/generated/dart_options.pb.dart
index 340247f..6de543c 100644
--- a/protoc_plugin/lib/src/generated/dart_options.pb.dart
+++ b/protoc_plugin/lib/src/generated/dart_options.pb.dart
@@ -164,14 +164,14 @@
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Imports>(create);
static Imports? _defaultInstance;
- /// Mixins to be used on messages in this file.
- /// These mixins are in addition to internally defined mixins (e.g PbMapMixin)
- /// and may override them.
+ /// Mixins to be used on messages in this file.
+ /// These mixins are in addition to internally defined mixins (e.g PbMapMixin)
+ /// and may override them.
///
- /// Warning: mixins are experimental. The protoc Dart plugin doesn't check
- /// for name conflicts between mixin class members and generated class members,
- /// so the generated code may contain errors. Therefore, running dartanalyzer
- /// on the generated file is a good idea.
+ /// Warning: mixins are experimental. The protoc Dart plugin doesn't check
+ /// for name conflicts between mixin class members and generated class members,
+ /// so the generated code may contain errors. Therefore, running dartanalyzer
+ /// on the generated file is a good idea.
@$pb.TagNumber(1)
$pb.PbList<DartMixin> get mixins => $_getList(0);
}
diff --git a/protoc_plugin/lib/src/generated/descriptor.pb.dart b/protoc_plugin/lib/src/generated/descriptor.pb.dart
index a4dfd4c..b505a40 100644
--- a/protoc_plugin/lib/src/generated/descriptor.pb.dart
+++ b/protoc_plugin/lib/src/generated/descriptor.pb.dart
@@ -948,27 +948,27 @@
@$pb.TagNumber(10)
void clearJsonName() => $_clearField(10);
- /// If true, this is a proto3 "optional". When a proto3 field is optional, it
- /// tracks presence regardless of field type.
+ /// If true, this is a proto3 "optional". When a proto3 field is optional, it
+ /// tracks presence regardless of field type.
///
- /// When proto3_optional is true, this field must be belong to a oneof to
- /// signal to old proto3 clients that presence is tracked for this field. This
- /// oneof is known as a "synthetic" oneof, and this field must be its sole
- /// member (each proto3 optional field gets its own synthetic oneof). Synthetic
- /// oneofs exist in the descriptor only, and do not generate any API. Synthetic
- /// oneofs must be ordered after all "real" oneofs.
+ /// When proto3_optional is true, this field must be belong to a oneof to
+ /// signal to old proto3 clients that presence is tracked for this field. This
+ /// oneof is known as a "synthetic" oneof, and this field must be its sole
+ /// member (each proto3 optional field gets its own synthetic oneof). Synthetic
+ /// oneofs exist in the descriptor only, and do not generate any API. Synthetic
+ /// oneofs must be ordered after all "real" oneofs.
///
- /// For message fields, proto3_optional doesn't create any semantic change,
- /// since non-repeated message fields always track presence. However it still
- /// indicates the semantic detail of whether the user wrote "optional" or not.
- /// This can be useful for round-tripping the .proto file. For consistency we
- /// give message fields a synthetic oneof also, even though it is not required
- /// to track presence. This is especially important because the parser can't
- /// tell if a field is a message or an enum, so it must always create a
- /// synthetic oneof.
+ /// For message fields, proto3_optional doesn't create any semantic change,
+ /// since non-repeated message fields always track presence. However it still
+ /// indicates the semantic detail of whether the user wrote "optional" or not.
+ /// This can be useful for round-tripping the .proto file. For consistency we
+ /// give message fields a synthetic oneof also, even though it is not required
+ /// to track presence. This is especially important because the parser can't
+ /// tell if a field is a message or an enum, so it must always create a
+ /// synthetic oneof.
///
- /// Proto2 optional fields do not set this flag, because they already indicate
- /// optional with `LABEL_OPTIONAL`.
+ /// Proto2 optional fields do not set this flag, because they already indicate
+ /// optional with `LABEL_OPTIONAL`.
@$pb.TagNumber(17)
$core.bool get proto3Optional => $_getBF(10);
@$pb.TagNumber(17)
@@ -1065,12 +1065,12 @@
OneofOptions ensureOptions() => $_ensure(1);
}
-/// Range of reserved numeric values. Reserved values may not be used by
-/// entries in the same enum. Reserved ranges may not overlap.
+/// Range of reserved numeric values. Reserved values may not be used by
+/// entries in the same enum. Reserved ranges may not overlap.
///
-/// Note that this is distinct from DescriptorProto.ReservedRange in that it
-/// is inclusive such that it can appropriately represent the entire int32
-/// domain.
+/// Note that this is distinct from DescriptorProto.ReservedRange in that it
+/// is inclusive such that it can appropriately represent the entire int32
+/// domain.
class EnumDescriptorProto_EnumReservedRange extends $pb.GeneratedMessage {
factory EnumDescriptorProto_EnumReservedRange({
$core.int? start,
@@ -1861,16 +1861,16 @@
@$pb.TagNumber(11)
void clearGoPackage() => $_clearField(11);
- /// Should generic services be generated in each language? "Generic" services
- /// are not specific to any particular RPC system. They are generated by the
- /// main code generators in each language (without additional plugins).
- /// Generic services were the only kind of service generation supported by
- /// early versions of google.protobuf.
+ /// Should generic services be generated in each language? "Generic" services
+ /// are not specific to any particular RPC system. They are generated by the
+ /// main code generators in each language (without additional plugins).
+ /// Generic services were the only kind of service generation supported by
+ /// early versions of google.protobuf.
///
- /// Generic services are now considered deprecated in favor of using plugins
- /// that generate code specific to your particular RPC system. Therefore,
- /// these default to false. Old code which depends on generic services should
- /// explicitly set them to true.
+ /// Generic services are now considered deprecated in favor of using plugins
+ /// that generate code specific to your particular RPC system. Therefore,
+ /// these default to false. Old code which depends on generic services should
+ /// explicitly set them to true.
@$pb.TagNumber(16)
$core.bool get ccGenericServices => $_getBF(5);
@$pb.TagNumber(16)
@@ -2163,24 +2163,24 @@
$pb.GeneratedMessage.$_defaultFor<MessageOptions>(create);
static MessageOptions? _defaultInstance;
- /// Set true to use the old proto1 MessageSet wire format for extensions.
- /// This is provided for backwards-compatibility with the MessageSet wire
- /// format. You should not use this for any other reason: It's less
- /// efficient, has fewer features, and is more complicated.
+ /// Set true to use the old proto1 MessageSet wire format for extensions.
+ /// This is provided for backwards-compatibility with the MessageSet wire
+ /// format. You should not use this for any other reason: It's less
+ /// efficient, has fewer features, and is more complicated.
///
- /// The message must be defined exactly as follows:
- /// message Foo {
- /// option message_set_wire_format = true;
- /// extensions 4 to max;
- /// }
- /// Note that the message cannot have any defined fields; MessageSets only
- /// have extensions.
+ /// The message must be defined exactly as follows:
+ /// message Foo {
+ /// option message_set_wire_format = true;
+ /// extensions 4 to max;
+ /// }
+ /// Note that the message cannot have any defined fields; MessageSets only
+ /// have extensions.
///
- /// All extensions of your type must be singular messages; e.g. they cannot
- /// be int32s, enums, or repeated messages.
+ /// All extensions of your type must be singular messages; e.g. they cannot
+ /// be int32s, enums, or repeated messages.
///
- /// Because this is an option, the above two restrictions are not enforced by
- /// the protocol compiler.
+ /// Because this is an option, the above two restrictions are not enforced by
+ /// the protocol compiler.
@$pb.TagNumber(1)
$core.bool get messageSetWireFormat => $_getBF(0);
@$pb.TagNumber(1)
@@ -2224,27 +2224,27 @@
@$pb.TagNumber(3)
void clearDeprecated() => $_clearField(3);
- /// Whether the message is an automatically generated map entry type for the
- /// maps field.
+ /// Whether the message is an automatically generated map entry type for the
+ /// maps field.
///
- /// For maps fields:
- /// map<KeyType, ValueType> map_field = 1;
- /// The parsed descriptor looks like:
- /// message MapFieldEntry {
- /// option map_entry = true;
- /// optional KeyType key = 1;
- /// optional ValueType value = 2;
- /// }
- /// repeated MapFieldEntry map_field = 1;
+ /// For maps fields:
+ /// map<KeyType, ValueType> map_field = 1;
+ /// The parsed descriptor looks like:
+ /// message MapFieldEntry {
+ /// option map_entry = true;
+ /// optional KeyType key = 1;
+ /// optional ValueType value = 2;
+ /// }
+ /// repeated MapFieldEntry map_field = 1;
///
- /// Implementations may choose not to generate the map_entry=true message, but
- /// use a native map in the target language to hold the keys and values.
- /// The reflection APIs in such implementations still need to work as
- /// if the field is a repeated message field.
+ /// Implementations may choose not to generate the map_entry=true message, but
+ /// use a native map in the target language to hold the keys and values.
+ /// The reflection APIs in such implementations still need to work as
+ /// if the field is a repeated message field.
///
- /// NOTE: Do not set the option in .proto files. Always use the maps syntax
- /// instead. The option should only be implicitly set by the proto compiler
- /// parser.
+ /// NOTE: Do not set the option in .proto files. Always use the maps syntax
+ /// instead. The option should only be implicitly set by the proto compiler
+ /// parser.
@$pb.TagNumber(7)
$core.bool get mapEntry => $_getBF(3);
@$pb.TagNumber(7)
@@ -2400,34 +2400,34 @@
@$pb.TagNumber(3)
void clearDeprecated() => $_clearField(3);
- /// Should this field be parsed lazily? Lazy applies only to message-type
- /// fields. It means that when the outer message is initially parsed, the
- /// inner message's contents will not be parsed but instead stored in encoded
- /// form. The inner message will actually be parsed when it is first accessed.
+ /// Should this field be parsed lazily? Lazy applies only to message-type
+ /// fields. It means that when the outer message is initially parsed, the
+ /// inner message's contents will not be parsed but instead stored in encoded
+ /// form. The inner message will actually be parsed when it is first accessed.
///
- /// This is only a hint. Implementations are free to choose whether to use
- /// eager or lazy parsing regardless of the value of this option. However,
- /// setting this option true suggests that the protocol author believes that
- /// using lazy parsing on this field is worth the additional bookkeeping
- /// overhead typically needed to implement it.
+ /// This is only a hint. Implementations are free to choose whether to use
+ /// eager or lazy parsing regardless of the value of this option. However,
+ /// setting this option true suggests that the protocol author believes that
+ /// using lazy parsing on this field is worth the additional bookkeeping
+ /// overhead typically needed to implement it.
///
- /// This option does not affect the public interface of any generated code;
- /// all method signatures remain the same. Furthermore, thread-safety of the
- /// interface is not affected by this option; const methods remain safe to
- /// call from multiple threads concurrently, while non-const methods continue
- /// to require exclusive access.
+ /// This option does not affect the public interface of any generated code;
+ /// all method signatures remain the same. Furthermore, thread-safety of the
+ /// interface is not affected by this option; const methods remain safe to
+ /// call from multiple threads concurrently, while non-const methods continue
+ /// to require exclusive access.
///
///
- /// Note that implementations may choose not to check required fields within
- /// a lazy sub-message. That is, calling IsInitialized() on the outer message
- /// may return true even if the inner message has missing required fields.
- /// This is necessary because otherwise the inner message would have to be
- /// parsed in order to perform the check, defeating the purpose of lazy
- /// parsing. An implementation which chooses not to check required fields
- /// must be consistent about it. That is, for any particular sub-message, the
- /// implementation must either *always* check its required fields, or *never*
- /// check its required fields, regardless of whether or not the message has
- /// been parsed.
+ /// Note that implementations may choose not to check required fields within
+ /// a lazy sub-message. That is, calling IsInitialized() on the outer message
+ /// may return true even if the inner message has missing required fields.
+ /// This is necessary because otherwise the inner message would have to be
+ /// parsed in order to perform the check, defeating the purpose of lazy
+ /// parsing. An implementation which chooses not to check required fields
+ /// must be consistent about it. That is, for any particular sub-message, the
+ /// implementation must either *always* check its required fields, or *never*
+ /// check its required fields, regardless of whether or not the message has
+ /// been parsed.
@$pb.TagNumber(5)
$core.bool get lazy => $_getBF(3);
@$pb.TagNumber(5)
@@ -2440,17 +2440,17 @@
@$pb.TagNumber(5)
void clearLazy() => $_clearField(5);
- /// The jstype option determines the JavaScript type used for values of the
- /// field. The option is permitted only for 64 bit integral and fixed types
- /// (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
- /// is represented as JavaScript string, which avoids loss of precision that
- /// can happen when a large value is converted to a floating point JavaScript.
- /// Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
- /// use the JavaScript "number" type. The behavior of the default option
- /// JS_NORMAL is implementation dependent.
+ /// The jstype option determines the JavaScript type used for values of the
+ /// field. The option is permitted only for 64 bit integral and fixed types
+ /// (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
+ /// is represented as JavaScript string, which avoids loss of precision that
+ /// can happen when a large value is converted to a floating point JavaScript.
+ /// Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
+ /// use the JavaScript "number" type. The behavior of the default option
+ /// JS_NORMAL is implementation dependent.
///
- /// This option is an enum to permit additional types to be added, e.g.
- /// goog.math.Integer.
+ /// This option is an enum to permit additional types to be added, e.g.
+ /// goog.math.Integer.
@$pb.TagNumber(6)
FieldOptions_JSType get jstype => $_getN(4);
@$pb.TagNumber(6)
@@ -3211,29 +3211,29 @@
$pb.GeneratedMessage.$_defaultFor<SourceCodeInfo_Location>(create);
static SourceCodeInfo_Location? _defaultInstance;
- /// Identifies which part of the FileDescriptorProto was defined at this
- /// location.
+ /// Identifies which part of the FileDescriptorProto was defined at this
+ /// location.
///
- /// Each element is a field number or an index. They form a path from
- /// the root FileDescriptorProto to the place where the definition. For
- /// example, this path:
- /// [ 4, 3, 2, 7, 1 ]
- /// refers to:
- /// file.message_type(3) // 4, 3
- /// .field(7) // 2, 7
- /// .name() // 1
- /// This is because FileDescriptorProto.message_type has field number 4:
- /// repeated DescriptorProto message_type = 4;
- /// and DescriptorProto.field has field number 2:
- /// repeated FieldDescriptorProto field = 2;
- /// and FieldDescriptorProto.name has field number 1:
- /// optional string name = 1;
+ /// Each element is a field number or an index. They form a path from
+ /// the root FileDescriptorProto to the place where the definition. For
+ /// example, this path:
+ /// [ 4, 3, 2, 7, 1 ]
+ /// refers to:
+ /// file.message_type(3) // 4, 3
+ /// .field(7) // 2, 7
+ /// .name() // 1
+ /// This is because FileDescriptorProto.message_type has field number 4:
+ /// repeated DescriptorProto message_type = 4;
+ /// and DescriptorProto.field has field number 2:
+ /// repeated FieldDescriptorProto field = 2;
+ /// and FieldDescriptorProto.name has field number 1:
+ /// optional string name = 1;
///
- /// Thus, the above path gives the location of a field name. If we removed
- /// the last element:
- /// [ 4, 3, 2, 7 ]
- /// this path refers to the whole field declaration (from the beginning
- /// of the label to the terminating semicolon).
+ /// Thus, the above path gives the location of a field name. If we removed
+ /// the last element:
+ /// [ 4, 3, 2, 7 ]
+ /// this path refers to the whole field declaration (from the beginning
+ /// of the label to the terminating semicolon).
@$pb.TagNumber(1)
$pb.PbList<$core.int> get path => $_getList(0);
@@ -3245,53 +3245,53 @@
@$pb.TagNumber(2)
$pb.PbList<$core.int> get span => $_getList(1);
- /// If this SourceCodeInfo represents a complete declaration, these are any
- /// comments appearing before and after the declaration which appear to be
- /// attached to the declaration.
+ /// If this SourceCodeInfo represents a complete declaration, these are any
+ /// comments appearing before and after the declaration which appear to be
+ /// attached to the declaration.
///
- /// A series of line comments appearing on consecutive lines, with no other
- /// tokens appearing on those lines, will be treated as a single comment.
+ /// A series of line comments appearing on consecutive lines, with no other
+ /// tokens appearing on those lines, will be treated as a single comment.
///
- /// leading_detached_comments will keep paragraphs of comments that appear
- /// before (but not connected to) the current element. Each paragraph,
- /// separated by empty lines, will be one comment element in the repeated
- /// field.
+ /// leading_detached_comments will keep paragraphs of comments that appear
+ /// before (but not connected to) the current element. Each paragraph,
+ /// separated by empty lines, will be one comment element in the repeated
+ /// field.
///
- /// Only the comment content is provided; comment markers (e.g. //) are
- /// stripped out. For block comments, leading whitespace and an asterisk
- /// will be stripped from the beginning of each line other than the first.
- /// Newlines are included in the output.
+ /// Only the comment content is provided; comment markers (e.g. //) are
+ /// stripped out. For block comments, leading whitespace and an asterisk
+ /// will be stripped from the beginning of each line other than the first.
+ /// Newlines are included in the output.
///
- /// Examples:
+ /// Examples:
///
- /// optional int32 foo = 1; // Comment attached to foo.
- /// // Comment attached to bar.
- /// optional int32 bar = 2;
+ /// optional int32 foo = 1; // Comment attached to foo.
+ /// // Comment attached to bar.
+ /// optional int32 bar = 2;
///
- /// optional string baz = 3;
- /// // Comment attached to baz.
- /// // Another line attached to baz.
+ /// optional string baz = 3;
+ /// // Comment attached to baz.
+ /// // Another line attached to baz.
///
- /// // Comment attached to qux.
- /// //
- /// // Another line attached to qux.
- /// optional double qux = 4;
+ /// // Comment attached to qux.
+ /// //
+ /// // Another line attached to qux.
+ /// optional double qux = 4;
///
- /// // Detached comment for corge. This is not leading or trailing comments
- /// // to qux or corge because there are blank lines separating it from
- /// // both.
+ /// // Detached comment for corge. This is not leading or trailing comments
+ /// // to qux or corge because there are blank lines separating it from
+ /// // both.
///
- /// // Detached comment for corge paragraph 2.
+ /// // Detached comment for corge paragraph 2.
///
- /// optional string corge = 5;
- /// /* Block comment attached
- /// * to corge. Leading asterisks
- /// * will be removed. */
- /// /* Block comment attached to
- /// * grault. */
- /// optional int32 grault = 6;
+ /// optional string corge = 5;
+ /// /* Block comment attached
+ /// * to corge. Leading asterisks
+ /// * will be removed. */
+ /// /* Block comment attached to
+ /// * grault. */
+ /// optional int32 grault = 6;
///
- /// // ignored detached comments.
+ /// // ignored detached comments.
@$pb.TagNumber(3)
$core.String get leadingComments => $_getSZ(2);
@$pb.TagNumber(3)
@@ -3373,49 +3373,49 @@
$pb.GeneratedMessage.$_defaultFor<SourceCodeInfo>(create);
static SourceCodeInfo? _defaultInstance;
- /// A Location identifies a piece of source code in a .proto file which
- /// corresponds to a particular definition. This information is intended
- /// to be useful to IDEs, code indexers, documentation generators, and similar
- /// tools.
+ /// A Location identifies a piece of source code in a .proto file which
+ /// corresponds to a particular definition. This information is intended
+ /// to be useful to IDEs, code indexers, documentation generators, and similar
+ /// tools.
///
- /// For example, say we have a file like:
- /// message Foo {
- /// optional string foo = 1;
- /// }
- /// Let's look at just the field definition:
- /// optional string foo = 1;
- /// ^ ^^ ^^ ^ ^^^
- /// a bc de f ghi
- /// We have the following locations:
- /// span path represents
- /// [a,i) [ 4, 0, 2, 0 ] The whole field definition.
- /// [a,b) [ 4, 0, 2, 0, 4 ] The label (optional).
- /// [c,d) [ 4, 0, 2, 0, 5 ] The type (string).
- /// [e,f) [ 4, 0, 2, 0, 1 ] The name (foo).
- /// [g,h) [ 4, 0, 2, 0, 3 ] The number (1).
+ /// For example, say we have a file like:
+ /// message Foo {
+ /// optional string foo = 1;
+ /// }
+ /// Let's look at just the field definition:
+ /// optional string foo = 1;
+ /// ^ ^^ ^^ ^ ^^^
+ /// a bc de f ghi
+ /// We have the following locations:
+ /// span path represents
+ /// [a,i) [ 4, 0, 2, 0 ] The whole field definition.
+ /// [a,b) [ 4, 0, 2, 0, 4 ] The label (optional).
+ /// [c,d) [ 4, 0, 2, 0, 5 ] The type (string).
+ /// [e,f) [ 4, 0, 2, 0, 1 ] The name (foo).
+ /// [g,h) [ 4, 0, 2, 0, 3 ] The number (1).
///
- /// Notes:
- /// - A location may refer to a repeated field itself (i.e. not to any
- /// particular index within it). This is used whenever a set of elements are
- /// logically enclosed in a single code segment. For example, an entire
- /// extend block (possibly containing multiple extension definitions) will
- /// have an outer location whose path refers to the "extensions" repeated
- /// field without an index.
- /// - Multiple locations may have the same path. This happens when a single
- /// logical declaration is spread out across multiple places. The most
- /// obvious example is the "extend" block again -- there may be multiple
- /// extend blocks in the same scope, each of which will have the same path.
- /// - A location's span is not always a subset of its parent's span. For
- /// example, the "extendee" of an extension declaration appears at the
- /// beginning of the "extend" block and is shared by all extensions within
- /// the block.
- /// - Just because a location's span is a subset of some other location's span
- /// does not mean that it is a descendant. For example, a "group" defines
- /// both a type and a field in a single declaration. Thus, the locations
- /// corresponding to the type and field and their components will overlap.
- /// - Code which tries to interpret locations should probably be designed to
- /// ignore those that it doesn't understand, as more types of locations could
- /// be recorded in the future.
+ /// Notes:
+ /// - A location may refer to a repeated field itself (i.e. not to any
+ /// particular index within it). This is used whenever a set of elements are
+ /// logically enclosed in a single code segment. For example, an entire
+ /// extend block (possibly containing multiple extension definitions) will
+ /// have an outer location whose path refers to the "extensions" repeated
+ /// field without an index.
+ /// - Multiple locations may have the same path. This happens when a single
+ /// logical declaration is spread out across multiple places. The most
+ /// obvious example is the "extend" block again -- there may be multiple
+ /// extend blocks in the same scope, each of which will have the same path.
+ /// - A location's span is not always a subset of its parent's span. For
+ /// example, the "extendee" of an extension declaration appears at the
+ /// beginning of the "extend" block and is shared by all extensions within
+ /// the block.
+ /// - Just because a location's span is a subset of some other location's span
+ /// does not mean that it is a descendant. For example, a "group" defines
+ /// both a type and a field in a single declaration. Thus, the locations
+ /// corresponding to the type and field and their components will overlap.
+ /// - Code which tries to interpret locations should probably be designed to
+ /// ignore those that it doesn't understand, as more types of locations could
+ /// be recorded in the future.
@$pb.TagNumber(1)
$pb.PbList<SourceCodeInfo_Location> get location => $_getList(0);
}
diff --git a/protoc_plugin/lib/src/generated/plugin.pb.dart b/protoc_plugin/lib/src/generated/plugin.pb.dart
index e50ab70..30c8a8d 100644
--- a/protoc_plugin/lib/src/generated/plugin.pb.dart
+++ b/protoc_plugin/lib/src/generated/plugin.pb.dart
@@ -236,20 +236,20 @@
@$pb.TagNumber(3)
Version ensureCompilerVersion() => $_ensure(2);
- /// FileDescriptorProtos for all files in files_to_generate and everything
- /// they import. The files will appear in topological order, so each file
- /// appears before any file that imports it.
+ /// FileDescriptorProtos for all files in files_to_generate and everything
+ /// they import. The files will appear in topological order, so each file
+ /// appears before any file that imports it.
///
- /// protoc guarantees that all proto_files will be written after
- /// the fields above, even though this is not technically guaranteed by the
- /// protobuf wire format. This theoretically could allow a plugin to stream
- /// in the FileDescriptorProtos and handle them one by one rather than read
- /// the entire set into memory at once. However, as of this writing, this
- /// is not similarly optimized on protoc's end -- it will store all fields in
- /// memory at once before sending them to the plugin.
+ /// protoc guarantees that all proto_files will be written after
+ /// the fields above, even though this is not technically guaranteed by the
+ /// protobuf wire format. This theoretically could allow a plugin to stream
+ /// in the FileDescriptorProtos and handle them one by one rather than read
+ /// the entire set into memory at once. However, as of this writing, this
+ /// is not similarly optimized on protoc's end -- it will store all fields in
+ /// memory at once before sending them to the plugin.
///
- /// Type names of fields and extensions in the FileDescriptorProto are always
- /// fully qualified.
+ /// Type names of fields and extensions in the FileDescriptorProto are always
+ /// fully qualified.
@$pb.TagNumber(15)
$pb.PbList<$0.FileDescriptorProto> get protoFile => $_getList(3);
}
@@ -323,17 +323,17 @@
$pb.GeneratedMessage.$_defaultFor<CodeGeneratorResponse_File>(create);
static CodeGeneratorResponse_File? _defaultInstance;
- /// The file name, relative to the output directory. The name must not
- /// contain "." or ".." components and must be relative, not be absolute (so,
- /// the file cannot lie outside the output directory). "/" must be used as
- /// the path separator, not "\".
+ /// The file name, relative to the output directory. The name must not
+ /// contain "." or ".." components and must be relative, not be absolute (so,
+ /// the file cannot lie outside the output directory). "/" must be used as
+ /// the path separator, not "\".
///
- /// If the name is omitted, the content will be appended to the previous
- /// file. This allows the generator to break large files into small chunks,
- /// and allows the generated text to be streamed back to protoc so that large
- /// files need not reside completely in memory at one time. Note that as of
- /// this writing protoc does not optimize for this -- it will read the entire
- /// CodeGeneratorResponse before writing files to disk.
+ /// If the name is omitted, the content will be appended to the previous
+ /// file. This allows the generator to break large files into small chunks,
+ /// and allows the generated text to be streamed back to protoc so that large
+ /// files need not reside completely in memory at one time. Note that as of
+ /// this writing protoc does not optimize for this -- it will read the entire
+ /// CodeGeneratorResponse before writing files to disk.
@$pb.TagNumber(1)
$core.String get name => $_getSZ(0);
@$pb.TagNumber(1)
@@ -346,43 +346,43 @@
@$pb.TagNumber(1)
void clearName() => $_clearField(1);
- /// If non-empty, indicates that the named file should already exist, and the
- /// content here is to be inserted into that file at a defined insertion
- /// point. This feature allows a code generator to extend the output
- /// produced by another code generator. The original generator may provide
- /// insertion points by placing special annotations in the file that look
- /// like:
- /// @@protoc_insertion_point(NAME)
- /// The annotation can have arbitrary text before and after it on the line,
- /// which allows it to be placed in a comment. NAME should be replaced with
- /// an identifier naming the point -- this is what other generators will use
- /// as the insertion_point. Code inserted at this point will be placed
- /// immediately above the line containing the insertion point (thus multiple
- /// insertions to the same point will come out in the order they were added).
- /// The double-@ is intended to make it unlikely that the generated code
- /// could contain things that look like insertion points by accident.
+ /// If non-empty, indicates that the named file should already exist, and the
+ /// content here is to be inserted into that file at a defined insertion
+ /// point. This feature allows a code generator to extend the output
+ /// produced by another code generator. The original generator may provide
+ /// insertion points by placing special annotations in the file that look
+ /// like:
+ /// @@protoc_insertion_point(NAME)
+ /// The annotation can have arbitrary text before and after it on the line,
+ /// which allows it to be placed in a comment. NAME should be replaced with
+ /// an identifier naming the point -- this is what other generators will use
+ /// as the insertion_point. Code inserted at this point will be placed
+ /// immediately above the line containing the insertion point (thus multiple
+ /// insertions to the same point will come out in the order they were added).
+ /// The double-@ is intended to make it unlikely that the generated code
+ /// could contain things that look like insertion points by accident.
///
- /// For example, the C++ code generator places the following line in the
- /// .pb.h files that it generates:
- /// // @@protoc_insertion_point(namespace_scope)
- /// This line appears within the scope of the file's package namespace, but
- /// outside of any particular class. Another plugin can then specify the
- /// insertion_point "namespace_scope" to generate additional classes or
- /// other declarations that should be placed in this scope.
+ /// For example, the C++ code generator places the following line in the
+ /// .pb.h files that it generates:
+ /// // @@protoc_insertion_point(namespace_scope)
+ /// This line appears within the scope of the file's package namespace, but
+ /// outside of any particular class. Another plugin can then specify the
+ /// insertion_point "namespace_scope" to generate additional classes or
+ /// other declarations that should be placed in this scope.
///
- /// Note that if the line containing the insertion point begins with
- /// whitespace, the same whitespace will be added to every line of the
- /// inserted text. This is useful for languages like Python, where
- /// indentation matters. In these languages, the insertion point comment
- /// should be indented the same amount as any inserted code will need to be
- /// in order to work correctly in that context.
+ /// Note that if the line containing the insertion point begins with
+ /// whitespace, the same whitespace will be added to every line of the
+ /// inserted text. This is useful for languages like Python, where
+ /// indentation matters. In these languages, the insertion point comment
+ /// should be indented the same amount as any inserted code will need to be
+ /// in order to work correctly in that context.
///
- /// The code generator that generates the initial file and the one which
- /// inserts into it must both run as part of a single invocation of protoc.
- /// Code generators are executed in the order in which they appear on the
- /// command line.
+ /// The code generator that generates the initial file and the one which
+ /// inserts into it must both run as part of a single invocation of protoc.
+ /// Code generators are executed in the order in which they appear on the
+ /// command line.
///
- /// If |insertion_point| is present, |name| must also be present.
+ /// If |insertion_point| is present, |name| must also be present.
@$pb.TagNumber(2)
$core.String get insertionPoint => $_getSZ(1);
@$pb.TagNumber(2)
@@ -492,14 +492,14 @@
$pb.GeneratedMessage.$_defaultFor<CodeGeneratorResponse>(create);
static CodeGeneratorResponse? _defaultInstance;
- /// Error message. If non-empty, code generation failed. The plugin process
- /// should exit with status code zero even if it reports an error in this way.
+ /// Error message. If non-empty, code generation failed. The plugin process
+ /// should exit with status code zero even if it reports an error in this way.
///
- /// This should be used to indicate errors in .proto files which prevent the
- /// code generator from generating correct code. Errors which indicate a
- /// problem in protoc itself -- such as the input CodeGeneratorRequest being
- /// unparseable -- should be reported by writing a message to stderr and
- /// exiting with a non-zero status code.
+ /// This should be used to indicate errors in .proto files which prevent the
+ /// code generator from generating correct code. Errors which indicate a
+ /// problem in protoc itself -- such as the input CodeGeneratorRequest being
+ /// unparseable -- should be reported by writing a message to stderr and
+ /// exiting with a non-zero status code.
@$pb.TagNumber(1)
$core.String get error => $_getSZ(0);
@$pb.TagNumber(1)
diff --git a/protoc_plugin/lib/src/grpc_generator.dart b/protoc_plugin/lib/src/grpc_generator.dart
index 1d9257c..85ad5e9 100644
--- a/protoc_plugin/lib/src/grpc_generator.dart
+++ b/protoc_plugin/lib/src/grpc_generator.dart
@@ -10,16 +10,18 @@
/// The generator of the .pb.dart file that will contain this service.
final FileGenerator fileGen;
+ final int _serviceIndex;
+
/// The message types needed directly by this service.
///
/// The key is the fully qualified name.
/// Populated by [resolve].
- final _deps = <String, MessageGenerator>{};
+ final Map<String, MessageGenerator> _deps = {};
/// Maps each undefined type to a string describing its location.
///
/// Populated by [resolve].
- final _undefinedDeps = <String, String>{};
+ final Map<String, String> _undefinedDeps = {};
/// Fully-qualified gRPC service name.
late final String _fullServiceName;
@@ -31,9 +33,15 @@
late final String _serviceClassname;
/// List of gRPC methods.
- final _methods = <_GrpcMethod>[];
+ final List<_GrpcMethod> _methods = [];
- GrpcServiceGenerator(this._descriptor, this.fileGen) {
+ late final List<int> _serviceDescriptorPath = [
+ ...fileGen.fieldPath,
+ ClientApiGenerator.fileDescriptorServiceTag,
+ _serviceIndex,
+ ];
+
+ GrpcServiceGenerator(this._descriptor, this.fileGen, this._serviceIndex) {
final name = _descriptor.name;
final package = fileGen.package;
@@ -106,6 +114,10 @@
}
void _generateClient(IndentingWriter out) {
+ final commentBlock = fileGen.commentBlock(_serviceDescriptorPath);
+ if (commentBlock != null) {
+ out.println(commentBlock);
+ }
if (_descriptor.options.deprecated) {
out.println(
"@$coreImportPrefix.Deprecated('This service is deprecated')");
@@ -118,8 +130,8 @@
out.println();
out.println(
'$_clientClassname(super.channel, {super.options, super.interceptors});');
- for (final method in _methods) {
- method.generateClientStub(out);
+ for (var i = 0; i < _methods.length; i++) {
+ _methods[i].generateClientStub(out, this, i);
}
});
}
@@ -228,8 +240,22 @@
' ($coreImportPrefix.List<$coreImportPrefix.int> value) => $_responseType.fromBuffer(value));');
}
- void generateClientStub(IndentingWriter out) {
+ List<int> _methodDescriptorPath(GrpcServiceGenerator generator, int index) {
+ return [
+ ...generator._serviceDescriptorPath,
+ ClientApiGenerator.serviceDescriptorMethodTag,
+ index,
+ ];
+ }
+
+ void generateClientStub(IndentingWriter out,
+ GrpcServiceGenerator serviceGenerator, int methodIndex) {
out.println();
+ final commentBlock = serviceGenerator.fileGen
+ .commentBlock(_methodDescriptorPath(serviceGenerator, methodIndex));
+ if (commentBlock != null) {
+ out.println(commentBlock);
+ }
if (_deprecated) {
out.println(
'@$coreImportPrefix.Deprecated(\'This method is deprecated\')');
diff --git a/protoc_plugin/lib/src/message_generator.dart b/protoc_plugin/lib/src/message_generator.dart
index 8746559..f26cec3 100644
--- a/protoc_plugin/lib/src/message_generator.dart
+++ b/protoc_plugin/lib/src/message_generator.dart
@@ -68,8 +68,7 @@
final List<int> _fieldPathSegment;
@override
- late final List<int> fieldPath = List.from(parent!.fieldPath!)
- ..addAll(_fieldPathSegment);
+ late final List<int> fieldPath = [...parent!.fieldPath, ..._fieldPathSegment];
// populated by resolve()
late List<ProtobufField> _fieldList;
diff --git a/protoc_plugin/lib/src/shared.dart b/protoc_plugin/lib/src/shared.dart
index 446f12d..c2c729d 100644
--- a/protoc_plugin/lib/src/shared.dart
+++ b/protoc_plugin/lib/src/shared.dart
@@ -66,6 +66,9 @@
/// This is the internal method for [FileDescriptorProtoExt.commentBlock],
/// public to be able to test.
String? toDartComment(String value) {
+ // TODO: Handle converting proto references to Dart references.
+ // "[Foo][google.firestore.v1.Foo]" => to either "`Foo`" or "[Foo]".
+
if (value.isEmpty) return null;
var lines = LineSplitter.split(value).toList();
@@ -75,8 +78,10 @@
final leadingSpaces = _leadingSpaces.firstMatch(lines.first);
if (leadingSpaces != null) {
final prefix = leadingSpaces.group(0)!;
- if (lines.every((element) => element.startsWith(prefix))) {
- lines = lines.map((e) => e.substring(prefix.length)).toList();
+ if (lines.every((line) => line.isEmpty || line.startsWith(prefix))) {
+ lines = lines
+ .map((line) => line.isEmpty ? line : line.substring(prefix.length))
+ .toList();
}
}
diff --git a/protoc_plugin/pubspec.yaml b/protoc_plugin/pubspec.yaml
index ffd1465..c1c12a2 100644
--- a/protoc_plugin/pubspec.yaml
+++ b/protoc_plugin/pubspec.yaml
@@ -1,5 +1,5 @@
name: protoc_plugin
-version: 22.1.0
+version: 22.1.1-wip
description: A protobuf protoc compiler plugin used to generate Dart code.
repository: https://github.com/google/protobuf.dart/tree/master/protoc_plugin
diff --git a/protoc_plugin/test/shared_test.dart b/protoc_plugin/test/shared_test.dart
index f15f471..3c8fb07 100644
--- a/protoc_plugin/test/shared_test.dart
+++ b/protoc_plugin/test/shared_test.dart
@@ -26,5 +26,19 @@
/// with one indent - trailing whitespace removed''',
);
});
+
+ test('indent with blank lines', () {
+ expect(
+ toDartComment('''
+ This is indented.
+
+ This is indented.
+'''),
+ '''
+/// This is indented.
+///
+/// This is indented.''',
+ );
+ });
});
}