@ -10,6 +10,7 @@ import sys
import re
import re
from google . protobuf . compiler import plugin_pb2
from google . protobuf . compiler import plugin_pb2
from validate import validate_pb2
# Namespace prefix for Envoy APIs.
# Namespace prefix for Envoy APIs.
ENVOY_API_NAMESPACE_PREFIX = ' .envoy.api.v2. '
ENVOY_API_NAMESPACE_PREFIX = ' .envoy.api.v2. '
@ -23,6 +24,7 @@ UNICODE_INVISIBLE_SEPARATOR = u'\u2063'
# Page/section titles with special prefixes in the proto comments
# Page/section titles with special prefixes in the proto comments
DOC_TITLE_REGEX = ' protodoc-title: \ s([^ \n ]+) \n \n ? '
DOC_TITLE_REGEX = ' protodoc-title: \ s([^ \n ]+) \n \n ? '
class ProtodocError ( Exception ) :
class ProtodocError ( Exception ) :
""" Base error class for the protodoc module. """
""" Base error class for the protodoc module. """
@ -151,9 +153,11 @@ def FormatHeaderFromFile(style, file_level_comment, alt):
m = re . search ( DOC_TITLE_REGEX , file_level_comment )
m = re . search ( DOC_TITLE_REGEX , file_level_comment )
if m :
if m :
# remove title hint and any new lines that follow
# remove title hint and any new lines that follow
return FormatHeader ( style , m . group ( 1 ) ) , re . sub ( DOC_TITLE_REGEX , ' ' , file_level_comment )
return FormatHeader ( style , m . group ( 1 ) ) , re . sub ( DOC_TITLE_REGEX , ' ' ,
file_level_comment )
return FormatHeader ( style , alt ) , file_level_comment
return FormatHeader ( style , alt ) , file_level_comment
def FormatFieldTypeAsJson ( type_context , field ) :
def FormatFieldTypeAsJson ( type_context , field ) :
""" Format FieldDescriptorProto.Type as a pseudo-JSON string.
""" Format FieldDescriptorProto.Type as a pseudo-JSON string.
@ -242,8 +246,14 @@ def FormatFieldType(type_context, field):
field . TYPE_DOUBLE : ' double ' ,
field . TYPE_DOUBLE : ' double ' ,
field . TYPE_FLOAT : ' float ' ,
field . TYPE_FLOAT : ' float ' ,
field . TYPE_INT32 : ' int32 ' ,
field . TYPE_INT32 : ' int32 ' ,
field . TYPE_SFIXED32 : ' int32 ' ,
field . TYPE_SINT32 : ' int32 ' ,
field . TYPE_FIXED32 : ' uint32 ' ,
field . TYPE_UINT32 : ' uint32 ' ,
field . TYPE_UINT32 : ' uint32 ' ,
field . TYPE_INT64 : ' int64 ' ,
field . TYPE_INT64 : ' int64 ' ,
field . TYPE_SFIXED64 : ' int64 ' ,
field . TYPE_SINT64 : ' int64 ' ,
field . TYPE_FIXED64 : ' uint64 ' ,
field . TYPE_UINT64 : ' uint64 ' ,
field . TYPE_UINT64 : ' uint64 ' ,
field . TYPE_BOOL : ' bool ' ,
field . TYPE_BOOL : ' bool ' ,
field . TYPE_STRING : ' string ' ,
field . TYPE_STRING : ' string ' ,
@ -301,8 +311,15 @@ def FormatFieldAsDefinitionListItem(type_context, field):
else :
else :
oneof_comment = ' '
oneof_comment = ' '
anchor = FormatAnchor ( FieldCrossRefLabel ( type_context . name ) )
anchor = FormatAnchor ( FieldCrossRefLabel ( type_context . name ) )
comment = ' ( %s ) ' % FormatFieldType (
annotations = [ ]
type_context , field ) + type_context . LeadingCommentPathLookup ( )
if field . options . HasExtension ( validate_pb2 . rules ) :
rule = field . options . Extensions [ validate_pb2 . rules ]
if rule . HasField ( ' message ' ) :
if rule . message . required :
annotations . append ( ' *REQUIRED* ' )
comment = ' ( %s ) ' % ' , ' . join (
[ FormatFieldType ( type_context , field ) ] + annotations
) + type_context . LeadingCommentPathLookup ( )
return anchor + field . name + ' \n ' + MapLines (
return anchor + field . name + ' \n ' + MapLines (
functools . partial ( Indent , 2 ) , comment + oneof_comment )
functools . partial ( Indent , 2 ) , comment + oneof_comment )
@ -345,7 +362,8 @@ def FormatMessage(type_context, msg):
map (
map (
functools . partial ( FormatFieldType , type_context ) ,
functools . partial ( FormatFieldType , type_context ) ,
nested_msg . field ) )
nested_msg . field ) )
for nested_msg in msg . nested_type if nested_msg . options . map_entry
for nested_msg in msg . nested_type
if nested_msg . options . map_entry
}
}
nested_msgs = ' \n ' . join (
nested_msgs = ' \n ' . join (
FormatMessage (
FormatMessage (
@ -425,16 +443,16 @@ def GenerateRst(proto_file):
source_code_info = SourceCodeInfo ( proto_file . source_code_info )
source_code_info = SourceCodeInfo ( proto_file . source_code_info )
# Find the earliest detached comment, attribute it to file level.
# Find the earliest detached comment, attribute it to file level.
# Also extract file level titles if any.
# Also extract file level titles if any.
header , comment = FormatHeaderFromFile ( ' = ' , source_code_info . file_level_comment ,
header , comment = FormatHeaderFromFile (
proto_file . name )
' = ' , source_code_info . file_level_comment , proto_file . name )
msgs = ' \n ' . join (
msgs = ' \n ' . join (
FormatMessage ( TypeContext ( source_code_info , [ 4 , index ] , msg . name ) , msg )
FormatMessage ( TypeContext ( source_code_info , [ 4 , index ] , msg . name ) , msg )
for index , msg in enumerate ( proto_file . message_type ) )
for index , msg in enumerate ( proto_file . message_type ) )
enums = ' \n ' . join (
enums = ' \n ' . join (
FormatEnum ( TypeContext ( source_code_info , [ 5 , index ] , enum . name ) , enum )
FormatEnum ( TypeContext ( source_code_info , [ 5 , index ] , enum . name ) , enum )
for index , enum in enumerate ( proto_file . enum_type ) )
for index , enum in enumerate ( proto_file . enum_type ) )
#debug_proto = FormatProtoAsBlockComment(proto_file.source_code_info )
debug_proto = FormatProtoAsBlockComment ( proto_file )
return header + comment + msgs + enums #+ debug_proto
return header + comment + msgs + enums #+ debug_proto
if __name__ == ' __main__ ' :
if __name__ == ' __main__ ' :