pseudomuto / protoc-gen-doc

Documentation generator plugin for Google Protocol Buffers
MIT License
2.61k stars 462 forks source link

custom options are missing from generated results #425

Open aSapien opened 4 years ago

aSapien commented 4 years ago

Hi, is there a plan to support custom, user-defined, options?

I'm willing to work on a PR if I can get some guidance and feedback.

Problem:

Custom options usages are missing from the generated descriptors:
Steps to reproduce:

  1. Given the following protos:

service.proto

syntax = "proto3";

package foo.bar;

import "google/protobuf/descriptor.proto";
import "extension.proto";

extend google.protobuf.MethodOptions {
    string a_method_option = 50007;
}

message Foo {
    string a = 1 [(a_field_option) = "field_option_value"];
}

message Bar {
    string a = 1;
}

service MyService {
    rpc GetResource(Foo) returns (Bar) {
        option (a_method_option) = "option_value";
    }
}

extension.proto

syntax = "proto2";

import "google/protobuf/descriptor.proto";

package foo.bar;

extend google.protobuf.FieldOptions {
    optional string a_field_option = 50008;
}
  1. Running protocc --doc_out=. --doc_opt=json,service.json service.proto will produce the following result (scalarValueTypes ommited):

Notice that a_field_option is completely missing from the result and a_method_option is only present as a definition, but not in usage.

NOTE: I noticed the efforts made and mentioned in issue #233, but they seem to hard-code a closed list of specific "supported" options.

service.json

{
  "files": [
    {
      "name": "service.proto",
      "description": "",
      "package": "foo.bar",
      "hasEnums": false,
      "hasExtensions": true,
      "hasMessages": true,
      "hasServices": true,
      "enums": [],
      "extensions": [
        {
          "name": "a_method_option",
          "longName": ".google.protobuf.MethodOptions.a_method_option",
          "fullName": ".google.protobuf.MethodOptions.a_method_option",
          "description": "",
          "label": "",
          "type": "string",
          "longType": "string",
          "fullType": "string",
          "number": 50007,
          "defaultValue": "",
          "containingType": "MethodOptions",
          "containingLongType": ".google.protobuf.MethodOptions",
          "containingFullType": "google.protobuf.MethodOptions"
        }
      ],
      "messages": [
        {
          "name": "Bar",
          "longName": "Bar",
          "fullName": "foo.bar.Bar",
          "description": "",
          "hasExtensions": false,
          "hasFields": true,
          "extensions": [],
          "fields": [
            {
              "name": "a",
              "description": "",
              "label": "",
              "type": "string",
              "longType": "string",
              "fullType": "string",
              "ismap": false,
              "defaultValue": ""
            }
          ]
        },
        {
          "name": "Foo",
          "longName": "Foo",
          "fullName": "foo.bar.Foo",
          "description": "",
          "hasExtensions": false,
          "hasFields": true,
          "extensions": [],
          "fields": [
            {
              "name": "a",
              "description": "",
              "label": "",
              "type": "string",
              "longType": "string",
              "fullType": "string",
              "ismap": false,
              "defaultValue": ""
            }
          ]
        }
      ],
      "services": [
        {
          "name": "MyService",
          "longName": "MyService",
          "fullName": "foo.bar.MyService",
          "description": "",
          "methods": [
            {
              "name": "GetResource",
              "description": "",
              "requestType": "Foo",
              "requestLongType": "Foo",
              "requestFullType": "foo.bar.Foo",
              "requestStreaming": false,
              "responseType": "Bar",
              "responseLongType": "Bar",
              "responseFullType": "foo.bar.Bar",
              "responseStreaming": false
            }
          ]
        }
      ]
    }
  ]
}

Ideally, I would like to see the options in the generated result like this:

{
  "files": [
+    {
+      "name": "extension.proto",
+      "description": "",
+      "package": "foo.bar",
+      "hasEnums": false,
+      "hasExtensions": true,
+      "hasMessages": false,
+      "hasServices": false,
+      "enums": [],
+      "extensions": [
+        {
+          "name": "a_field_option",
+          "longName": ".google.protobuf.FieldOptions.a_field_option",
+          "fullName": ".google.protobuf.FieldOptions.a_field_option",
+          "description": "",
+          "label": "",
+          "type": "string",
+          "longType": "string",
+          "fullType": "string",
+          "number": 50008,
+          "defaultValue": "",
+          "containingType": "MethodOptions",
+          "containingLongType": ".google.protobuf.FieldOptions",
+          "containingFullType": "google.protobuf.FieldOptions"
+        }
+      ]
+    },
    {
      "name": "service.proto",
      "description": "",
      "package": "foo.bar",
      "hasEnums": false,
      "hasExtensions": true,
      "hasMessages": true,
      "hasServices": true,
      "enums": [],
      "extensions": [
        {
          "name": "a_method_option",
          "longName": ".google.protobuf.MethodOptions.a_method_option",
          "fullName": ".google.protobuf.MethodOptions.a_method_option",
          "description": "",
          "label": "",
          "type": "string",
          "longType": "string",
          "fullType": "string",
          "number": 50007,
          "defaultValue": "",
          "containingType": "MethodOptions",
          "containingLongType": ".google.protobuf.MethodOptions",
          "containingFullType": "google.protobuf.MethodOptions"
        }
      ],
      "messages": [
        {
          "name": "Bar",
          "longName": "Bar",
          "fullName": "foo.bar.Bar",
          "description": "",
          "hasExtensions": false,
          "hasFields": true,
          "extensions": [],
          "fields": [
            {
              "name": "a",
              "description": "",
              "label": "",
              "type": "string",
              "longType": "string",
              "fullType": "string",
              "ismap": false,
              "defaultValue": ""
            }
          ]
        },
        {
          "name": "Foo",
          "longName": "Foo",
          "fullName": "foo.bar.Foo",
          "description": "",
          "hasExtensions": false,
          "hasFields": true,
          "extensions": [],
          "fields": [
            {
              "name": "a",
              "description": "",
              "label": "",
              "type": "string",
              "longType": "string",
              "fullType": "string",
              "ismap": false,
              "defaultValue": "",
+              "extensions": [                
+                {
+                  "fullName": ".google.protobuf.FieldOptions.a_field_option",
+                  "name": "a_field_option",
+                  "type": "string",
+                  "value": "field_option_value"
+                }
+              ]
            }
          ]
        }
      ],
      "services": [
        {
          "name": "MyService",
          "longName": "MyService",
          "fullName": "foo.bar.MyService",
          "description": "",
          "methods": [
            {
              "name": "GetResource",
              "description": "",
              "requestType": "Foo",
              "requestLongType": "Foo",
              "requestFullType": "foo.bar.Foo",
              "requestStreaming": false,
              "responseType": "Bar",
              "responseLongType": "Bar",
              "responseFullType": "foo.bar.Bar",
              "responseStreaming": false,
+              "extensions": [
+                {
+                  "fullName": ".google.protobuf.MethodOptions.a_method_option",
+                  "name": "a_method_option",
+                  "type": "string",
+                  "value": "option_value"
+                }
+              ]
            }
          ]
        }
      ]
    }
  ]

Any assistance on how to accomplish this and possible solutions discussions are highly appreciated.

Thanks!

barakt11 commented 4 years ago

@pseudomuto - can you assist? I find it really precious

mehran-prs commented 3 years ago

Any update?

jase88 commented 2 years ago

Would be a great feature if custom options would be considered.

https://developers.google.com/protocol-buffers/docs/proto#customoptions lists some usages on messages, fields, enums, services etc

bobtiernay-okta commented 2 years ago

Agreed. This would be highly valuable for a number of scenarios.

pseudomuto commented 2 years ago

I'm fairly swamped atm. Anyone interested in giving this a go? I think we'd need to add the feature to https://github.com/pseudomuto/protokit and then update the rendering code here to print out the custom option details.

abdelhalim commented 2 years ago

I'm seeing some code related to options in the HTML template. what is the overall status of Field Options support in protoc-gen-doc ? is it supported only for subset as described above, or there is support but it's limited to HTML ?

swinSpo commented 2 years ago

@pseudomuto can you give us an update on this please? This seems like a very important and useful feature.

renjiexu commented 1 year ago

Really looking forward to having this feature, bumping this thread again..