├── .gitignore ├── Makefile ├── README.md ├── go.mod ├── go.sum ├── main.go ├── main_test.go ├── templates ├── hugo-markdown.tmpl └── markdown.tmpl ├── testdata └── example1 │ ├── booking.md │ ├── booking.proto │ ├── field_presence.md │ ├── field_presence.proto │ ├── vehicle.md │ └── vehicle.proto ├── thirdparty ├── generate.go └── github.com │ ├── envoyproxy │ └── protoc-gen-validate │ │ └── validate │ │ └── validate.proto │ ├── mwitkow │ └── go-proto-validators │ │ └── validator.proto │ └── pseudomuto │ └── protokit │ └── fixtures │ └── extend.proto └── tmp └── .gitkeep /.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test 2 | test: tmp/googleapis 3 | go install 4 | protoc \ 5 | -I thirdparty \ 6 | -I tmp/googleapis \ 7 | -I testdata \ 8 | --apidocs_out=testdata/ \ 9 | --apidocs_opt=paths=source_relative \ 10 | testdata/example1/*.proto 11 | 12 | .PHONY: install 13 | install: 14 | go install 15 | 16 | tmp/googleapis: 17 | rm -rf tmp/googleapis tmp/protocolbuffers 18 | git clone --depth 1 https://github.com/googleapis/googleapis tmp/googleapis 19 | rm -rf tmp/googleapis/.git 20 | git clone --depth 1 https://github.com/protocolbuffers/protobuf tmp/protocolbuffers 21 | cp -r tmp/protocolbuffers/src/* tmp/googleapis/ 22 | rm -rf tmp/protocolbuffers 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # protoc-gen-apidocs 2 | 3 | `protoc-gen-apidocs` is a very simple and customizable protoc generator that translates .proto files into clean and readable markdown format. 4 | 5 | This is achieved by levearging the fantastic 6 | [protogen](https://pkg.go.dev/google.golang.org/protobuf/compiler/protogen) library and Go's 7 | built-in templating capabilties. 8 | 9 | ## Example Output 10 | 11 | **Vehicle.proto example** 12 | 13 | This example shows a variety of protobuf features including extensions and nested messages. 14 | 15 | * [Output markdown](./testdata/example1/vehicle.md) 16 | * [Source proto](./testdata/example1/vehicle.proto) 17 | 18 | 19 | **Booking.proto example** 20 | 21 | This example is relatively simple but shows streaming rpc endpoints properly handled. 22 | 23 | * [Output markdown](./testdata/example1/booking.md) 24 | * [Source proto](./testdata/example1/booking.proto) 25 | 26 | 27 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tmc/protoc-gen-apidocs 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/Masterminds/sprig v2.22.0+incompatible 7 | google.golang.org/protobuf v1.33.0 8 | ) 9 | 10 | require ( 11 | github.com/Masterminds/goutils v1.1.1 // indirect 12 | github.com/Masterminds/semver v1.5.0 // indirect 13 | github.com/golang/protobuf v1.5.4 // indirect 14 | github.com/google/uuid v1.4.0 // indirect 15 | github.com/huandu/xstrings v1.3.2 // indirect 16 | github.com/imdario/mergo v0.3.12 // indirect 17 | github.com/lyft/protoc-gen-star v0.6.0 // indirect 18 | github.com/mitchellh/copystructure v1.2.0 // indirect 19 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 20 | github.com/spf13/afero v1.11.0 // indirect 21 | golang.org/x/crypto v0.16.0 // indirect 22 | golang.org/x/text v0.14.0 // indirect 23 | ) 24 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= 2 | github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= 3 | github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= 4 | github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= 5 | github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= 6 | github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= 7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 9 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 10 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 11 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 12 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 13 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 14 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 15 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 16 | github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= 17 | github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 18 | github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= 19 | github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 20 | github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= 21 | github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= 22 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 23 | github.com/lyft/protoc-gen-star v0.6.0 h1:xOpFu4vwmIoUeUrRuAtdCrZZymT/6AkW/bsUWA506Fo= 24 | github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= 25 | github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= 26 | github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= 27 | github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= 28 | github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 29 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 30 | github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= 31 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 32 | github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= 33 | github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= 34 | github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= 35 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 36 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 37 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 38 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 39 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 40 | golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI= 41 | golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 42 | golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= 43 | golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= 44 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 45 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 46 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 47 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 48 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 49 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 50 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 51 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 52 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 53 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 54 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 55 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 56 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= 57 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 58 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= 59 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 60 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 61 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 62 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 63 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 64 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "embed" 5 | "flag" 6 | "fmt" 7 | htmltemplate "html/template" 8 | "io/fs" 9 | "os" 10 | "path/filepath" 11 | "regexp" 12 | "strings" 13 | "text/template" 14 | 15 | "github.com/Masterminds/sprig" 16 | "google.golang.org/protobuf/compiler/protogen" 17 | "google.golang.org/protobuf/reflect/protoreflect" 18 | "google.golang.org/protobuf/types/pluginpb" 19 | ) 20 | 21 | func main() { 22 | var flags flag.FlagSet 23 | format := flags.String("format", "markdown", "Format to use") 24 | templates := flags.String("templates", "", "Custom templates directory to use") 25 | trimPrefix := flags.String("trimprefix", "", "If supplied, this prefix will be removed from generated file paths.") 26 | 27 | opts := &protogen.Options{ 28 | ParamFunc: flags.Set, 29 | } 30 | opts.Run(func(gen *protogen.Plugin) error { 31 | gen.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL) 32 | genOpts := GenOpts{ 33 | Format: *format, 34 | TemplateDir: *templates, 35 | TrimPrefix: *trimPrefix, 36 | } 37 | for _, f := range gen.Files { 38 | if !f.Generate { 39 | continue 40 | } 41 | if err := genOpts.generateFile(gen, f); err != nil { 42 | return err 43 | } 44 | } 45 | return nil 46 | }) 47 | } 48 | 49 | // GenOpts hold options for generation. 50 | type GenOpts struct { 51 | Format string 52 | TemplateDir string 53 | TrimPrefix string 54 | } 55 | 56 | var formatFileSuffixes = map[string]string{ 57 | "markdown": "md", 58 | "hugo-markdown": "md", 59 | } 60 | 61 | // generateFile generates a _ascii.pb.go file containing gRPC service definitions. 62 | func (o *GenOpts) generateFile(gen *protogen.Plugin, file *protogen.File) error { 63 | suffix, ok := formatFileSuffixes[o.Format] 64 | if !ok { 65 | suffix = o.Format 66 | } 67 | filename := file.GeneratedFilenamePrefix + "." + suffix 68 | filename = strings.TrimPrefix(filename, o.TrimPrefix) 69 | g := gen.NewGeneratedFile(filename, file.GoImportPath) 70 | if err := o.renderTemplate(file, g); err != nil { 71 | return fmt.Errorf("issue generating %v: %w", filename, err) 72 | } 73 | return nil 74 | } 75 | 76 | func (o *GenOpts) relPath(t1, t2 protoreflect.Descriptor) string { 77 | path := "" 78 | cpf := filepath.Base(fmt.Sprint(t1.ParentFile().Path())) 79 | rpf := filepath.Base(fmt.Sprint(t2.ParentFile().Path())) 80 | if cpf != rpf { 81 | path, _ = filepath.Rel(cpf, rpf) 82 | path = strings.TrimSuffix(path, filepath.Ext(path)) 83 | path = strings.TrimPrefix(path, ".") 84 | path = fmt.Sprintf("%s.%s", path, formatFileSuffixes[o.Format]) 85 | } 86 | return path 87 | } 88 | 89 | func longName(d protoreflect.Descriptor) string { 90 | p := d.Parent() 91 | if p != nil && p.Parent() != nil { 92 | return fmt.Sprintf("%v.%v", p.Name(), d.Name()) 93 | } 94 | return fmt.Sprint(d.Name()) 95 | } 96 | 97 | func anchor(str interface{}) string { 98 | return specialCharsPattern.ReplaceAllString(strings.ReplaceAll(fmt.Sprint(str), "/", "_"), "-") 99 | } 100 | 101 | func (o *GenOpts) templateFuncMap() template.FuncMap { 102 | return map[string]interface{}{ 103 | "anchor": anchor, 104 | "long_name": longName, 105 | "field_type": func(f *protogen.Field) string { 106 | if f.Message != nil { 107 | return longName(f.Message.Desc) 108 | } 109 | if f.Enum != nil { 110 | return longName(f.Enum.Desc) 111 | } 112 | return fmt.Sprint(f.Desc.Kind()) 113 | }, 114 | "full_field_type": func(f *protogen.Field) string { 115 | if f.Message != nil { 116 | return fmt.Sprint(f.Message.Desc.FullName()) 117 | } 118 | if f.Enum != nil { 119 | return fmt.Sprint(f.Enum.Desc.FullName()) 120 | } 121 | return fmt.Sprint(f.Desc.Kind()) 122 | }, 123 | "is_primitive": func(f *protogen.Field) bool { 124 | // TODO: consider oneof, enum, ... 125 | k := f.Desc.Kind() 126 | nonPrim := k == protoreflect.EnumKind || k == protoreflect.MessageKind || k == protoreflect.GroupKind 127 | return !nonPrim 128 | }, 129 | "message_type": func(f *protogen.Message) string { 130 | if f == nil { 131 | return "(none)" 132 | } 133 | return fmt.Sprint(f.Desc.Name()) 134 | }, 135 | "full_message_type": func(f *protogen.Message) string { 136 | return fmt.Sprint(f.Desc.FullName()) 137 | }, 138 | "is_google_type": func(f *protogen.Field) bool { 139 | if f.Message != nil { 140 | return strings.HasPrefix(string(f.Message.Desc.FullName()), "google.") 141 | } 142 | if f.Enum != nil { 143 | return strings.HasPrefix(string(f.Enum.Desc.FullName()), "google.") 144 | } 145 | return false 146 | }, 147 | "type_link": func(f *protogen.Field) string { 148 | var t1, t2 protoreflect.Descriptor 149 | t1 = f.Desc 150 | if f.Message != nil { 151 | t2 = f.Message.Desc 152 | } 153 | if f.Enum != nil { 154 | t2 = f.Enum.Desc 155 | } 156 | if strings.HasPrefix(string(t2.FullName()), "google.") { 157 | return string(t2.FullName()) 158 | } 159 | fn := o.relPath(t1, t2) 160 | typ := anchor(fmt.Sprint(t2.FullName())) 161 | return fmt.Sprintf(`%s#%s`, fn, typ) 162 | }, 163 | "hugo_type_link": func(f *protogen.Field) string { 164 | // exclude google types: 165 | 166 | if f.Message != nil { 167 | if strings.HasPrefix(string(f.Message.Desc.FullName()), "google.") { 168 | return string(f.Message.Desc.FullName()) 169 | } 170 | fn := fmt.Sprint(f.Message.Desc.ParentFile().Path()) 171 | fn = filepath.Base(fn) 172 | fn = strings.TrimSuffix(fn, filepath.Ext(fn)) 173 | typ := anchor(fmt.Sprint(f.Message.Desc.FullName())) 174 | return fmt.Sprintf(`{{< relref "%s#%s" >}}`, fn, typ) 175 | } 176 | if f.Enum != nil { 177 | fn := fmt.Sprint(f.Enum.Desc.ParentFile().Path()) 178 | fn = filepath.Base(fn) 179 | fn = strings.TrimSuffix(fn, filepath.Ext(fn)) 180 | typ := anchor(fmt.Sprint(f.Enum.Desc.FullName())) 181 | return fmt.Sprintf(`{{< relref "%s#%s" >}}`, fn, typ) 182 | } 183 | return fmt.Sprintf(`#%s`, anchor(f.Desc.FullName())) 184 | }, 185 | "description": func(s interface{}) string { 186 | val := strings.TrimLeft(fmt.Sprint(s), "*/\n ") 187 | if strings.HasPrefix(val, "@exclude") { 188 | return "" 189 | } 190 | commentRe := regexp.MustCompile("\n// ?") 191 | return commentRe.ReplaceAllString(val, "\n") 192 | }, 193 | "p": pFilter, 194 | "para": paraFilter, 195 | "nobr": nobrFilter, 196 | } 197 | } 198 | 199 | //go:embed templates/* 200 | var defaultTemplates embed.FS 201 | 202 | func (o *GenOpts) getTemplateFS() (fs.FS, error) { 203 | if o.TemplateDir == "" { 204 | return fs.Sub(defaultTemplates, "templates") 205 | } 206 | tFS := os.DirFS(o.TemplateDir) 207 | return fs.Sub(tFS, o.TemplateDir) 208 | } 209 | 210 | func (o *GenOpts) renderTemplate(file *protogen.File, g *protogen.GeneratedFile) error { 211 | tFS, err := o.getTemplateFS() 212 | if err != nil { 213 | return err 214 | } 215 | t := template.New("file.tmpl").Funcs(o.templateFuncMap()).Funcs(sprig.TxtFuncMap()) 216 | t, err = t.ParseFS(tFS, fmt.Sprintf("%v.tmpl", o.Format)) 217 | if err != nil { 218 | return err 219 | } 220 | return t.ExecuteTemplate(g, "output", file) 221 | } 222 | 223 | // Template Helpers 224 | 225 | var ( 226 | paraPattern = regexp.MustCompile(`(\n|\r|\r\n)\s*`) 227 | spacePattern = regexp.MustCompile("( )+") 228 | multiNewlinePattern = regexp.MustCompile(`(\r\n|\r|\n){2,}`) 229 | specialCharsPattern = regexp.MustCompile(`[^a-zA-Z0-9_-]`) 230 | ) 231 | 232 | func pFilter(content string) htmltemplate.HTML { 233 | paragraphs := paraPattern.Split(content, -1) 234 | return htmltemplate.HTML(fmt.Sprintf("

%s

", strings.Join(paragraphs, "

"))) 235 | } 236 | 237 | func paraFilter(content string) string { 238 | paragraphs := paraPattern.Split(content, -1) 239 | return fmt.Sprintf("%s", strings.Join(paragraphs, "")) 240 | } 241 | 242 | func nobrFilter(content string) string { 243 | normalized := strings.Replace(content, "\r\n", "\n", -1) 244 | paragraphs := multiNewlinePattern.Split(normalized, -1) 245 | for i, p := range paragraphs { 246 | withoutCR := strings.Replace(p, "\r", " ", -1) 247 | withoutLF := strings.Replace(withoutCR, "\n", " ", -1) 248 | paragraphs[i] = spacePattern.ReplaceAllString(withoutLF, " ") 249 | } 250 | return strings.Join(paragraphs, "\n\n") 251 | } 252 | -------------------------------------------------------------------------------- /main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | func TestExamples(t *testing.T) { 6 | } 7 | -------------------------------------------------------------------------------- /templates/hugo-markdown.tmpl: -------------------------------------------------------------------------------- 1 | {{/*************************************************************** 2 | Markdown template for protoc-gen-apidocs 3 | 4 | This template is rendered once per incoming .proto file and 5 | defines the resulting output documentation. 6 | 7 | This file is organized into blocks via the go template "define" 8 | function and they are executed with the "template" function. 9 | ***************************************************************/}} 10 | 11 | {{/*************************************************************** 12 | Main output block 13 | ***************************************************************/}} 14 | {{define "output" -}} 15 | 16 | --- 17 | title: {{ .Desc.Package }} 18 | description: API Specification for the {{ .Desc.Package }} package. 19 | --- 20 | 21 |

Top

22 | 23 | 24 | {{range .Services}} 25 | {{template "service" .}} 26 | {{end}} 27 | 28 | 29 | {{ range .Messages }} 30 | {{template "message" .}} 31 | {{end}} 32 | 33 | 34 | {{range .Enums}} 35 | {{template "enum" .}} 36 | {{end}} 37 | 38 | 39 | {{if .Extensions}} 40 | 41 | 42 | ### Extensions 43 | | Extension | Type | Extension Point | Number | Description | 44 | | --------- | ---- | ---- | ------ | ----------- | 45 | {{range .Extensions -}} 46 | | {{.Desc.Name}} | {{.Desc.FullName}} | {{ .Extendee | message_type }} | {{.Desc.Number}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | 47 | {{end}} 48 | {{end}} 49 | 50 | {{end}} 51 | 52 | 53 | {{/*************************************************************** 54 | Service template 55 | ***************************************************************/}} 56 | {{define "service"}} 57 | 58 | 59 | ### {{.Desc.Name}} 60 | 61 | {{.Comments.Leading | description}} 62 | {{.Comments.Trailing | description}} 63 | 64 | | Method Name | Request Type | Response Type | Description | 65 | | ----------- | ------------ | ------------- | ------------| 66 | {{range .Methods -}} 67 | | {{.Desc.Name}} | [{{ .Input | message_type }}](#{{ .Input | full_message_type | anchor }}) | [{{ .Output | message_type }}](#{{ .Output | full_message_type | anchor }}){{if .Desc.IsStreamingServer}} stream{{end}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | 68 | {{end}} 69 | {{end}} 70 | 71 | 72 | 73 | {{/*************************************************************** 74 | Message template 75 | ***************************************************************/}} 76 | {{define "message"}} 77 | 78 | 79 | ### {{.Desc.Name}} 80 | 81 | {{.Comments.Leading | description}} 82 | {{.Comments.Trailing | description}} 83 | 84 | {{if .Fields}} 85 | | Field | Type | Description | 86 | | ----- | ---- | ----------- | 87 | {{range .Fields}}{{ if (not .Desc.ContainingOneof) }}{{template "field" .}}{{end}}{{end}} 88 | {{- end -}} 89 | {{range .Oneofs}}{{ if .Desc.IsSynthetic }}{{template "field" (index .Fields 0) }}{{else}}{{template "oneof" .}}{{end}}{{end}} 90 | 91 | {{if .Extensions}} 92 | | Extension | Type | Base | Number | Description | 93 | | --------- | ---- | ---- | ------ | ----------- | 94 | {{range .Extensions -}} 95 | | {{.Desc.Name}} | {{.Desc | long_name}} | {{.Parent | message_type}} | {{.Desc.Number}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | 96 | {{end}} 97 | {{end}} 98 | 99 | {{ range .Messages }} 100 | {{template "message" .}} 101 | {{end}} 102 | 103 | {{range .Enums}} 104 | {{template "enum" .}} 105 | {{end}} 106 | 107 | {{end}} 108 | 109 | {{/*************************************************************** 110 | Field template 111 | ***************************************************************/}} 112 | {{define "field" -}} 113 | | {{.Desc.Name }}{{ if .Desc.IsList }}[]{{ end }}{{ if .Desc.HasOptionalKeyword }} (optional){{ end }} | 114 | {{- if (or (is_primitive .) (is_google_type .)) -}} 115 | {{ field_type . }} 116 | {{- else -}} 117 | [{{ .| field_type }}]({{ hugo_type_link . }}) 118 | {{- end -}} 119 | | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr }} | 120 | {{end}} 121 | 122 | {{/*************************************************************** 123 | Oneof template 124 | This is kind of gross since GFM doesn't support colspan. 125 | ***************************************************************/}} 126 | {{define "oneof" -}} 127 | |Union field `{{ .Desc.Name }}`. {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr }} `{{ .Desc.Name }}` can be only one of the following:| 128 | {{range .Fields}}{{template "field" .}}{{end}} 129 | {{end}} 130 | 131 | {{/*************************************************************** 132 | Enum template 133 | ***************************************************************/}} 134 | {{define "enum" }} 135 | 136 | 137 | ### {{.Desc | long_name}} 138 | {{.Comments.Leading | description}} 139 | {{.Comments.Trailing | description}} 140 | 141 | | Name | Number | Description | 142 | | ---- | ------ | ----------- | 143 | {{range .Values -}} 144 | | {{.Desc.Name}} | {{.Desc.Number}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | 145 | {{end}} 146 | {{end}} 147 | -------------------------------------------------------------------------------- /templates/markdown.tmpl: -------------------------------------------------------------------------------- 1 | {{/*************************************************************** 2 | Markdown template for protoc-gen-apidocs 3 | 4 | This template is rendered once per incoming .proto file and 5 | defines the resulting output documentation. 6 | 7 | This file is organized into blocks via the go template "define" 8 | function and they are executed with the "template" function. 9 | ***************************************************************/}} 10 | 11 | {{/*************************************************************** 12 | Main output block 13 | ***************************************************************/}} 14 | {{define "output" -}} 15 | 16 | --- 17 | title: {{ .Desc.Package }} 18 | description: API Specification for the {{ .Desc.Package }} package. 19 | --- 20 | 21 |

Top

22 | 23 | 24 | {{range .Services}} 25 | {{template "service" .}} 26 | {{end}} 27 | 28 | 29 | {{ range .Messages }} 30 | {{template "message" .}} 31 | {{end}} 32 | 33 | 34 | {{range .Enums}} 35 | {{template "enum" .}} 36 | {{end}} 37 | 38 | 39 | {{if .Extensions}} 40 | 41 | 42 | ### Extensions 43 | | Extension | Type | Extension Point | Number | Description | 44 | | --------- | ---- | ---- | ------ | ----------- | 45 | {{range .Extensions -}} 46 | | {{.Desc.Name}} | {{.Desc.FullName}} | {{ .Extendee | message_type }} | {{.Desc.Number}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | 47 | {{end}} 48 | {{end}} 49 | 50 | {{end}} 51 | 52 | 53 | {{/*************************************************************** 54 | Service template 55 | ***************************************************************/}} 56 | {{define "service"}} 57 | 58 | 59 | ### {{.Desc.Name}} 60 | 61 | {{.Comments.Leading | description}} 62 | {{.Comments.Trailing | description}} 63 | 64 | | Method Name | Request Type | Response Type | Description | 65 | | ----------- | ------------ | ------------- | ------------| 66 | {{range .Methods -}} 67 | | {{.Desc.Name}} | [{{ .Input | message_type }}](#{{ .Input | full_message_type | anchor }}) | [{{ .Output | message_type }}](#{{ .Output | full_message_type | anchor }}){{if .Desc.IsStreamingServer}} stream{{end}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | 68 | {{end}} 69 | {{end}} 70 | 71 | 72 | 73 | {{/*************************************************************** 74 | Message template 75 | ***************************************************************/}} 76 | {{define "message"}} 77 | 78 | 79 | ### {{.Desc.Name}} 80 | 81 | {{.Comments.Leading | description}} 82 | {{.Comments.Trailing | description}} 83 | 84 | {{if .Fields}} 85 | | Field | Type | Description | 86 | | ----- | ---- | ----------- | 87 | {{range .Fields}}{{ if (not .Desc.ContainingOneof) }}{{template "field" .}}{{end}}{{end}} 88 | {{- end -}} 89 | 90 | {{range .Oneofs}}{{ if .Desc.IsSynthetic }}{{template "field" (index .Fields 0) }}{{else}}{{template "oneof" .}}{{end}}{{end}} 91 | 92 | {{if .Extensions}} 93 | | Extension | Type | Base | Number | Description | 94 | | --------- | ---- | ---- | ------ | ----------- | 95 | {{range .Extensions -}} 96 | | {{.Desc.Name}} | {{.Desc | long_name}} | {{.Parent | message_type}} | {{.Desc.Number}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | 97 | {{end}} 98 | {{end}} 99 | 100 | {{ range .Messages }} 101 | {{template "message" .}} 102 | {{end}} 103 | 104 | {{range .Enums}} 105 | {{template "enum" .}} 106 | {{end}} 107 | 108 | {{end}} 109 | 110 | {{/*************************************************************** 111 | Field template 112 | ***************************************************************/}} 113 | {{define "field" -}} 114 | | {{.Desc.Name }}{{ if .Desc.IsList }}[]{{ end }}{{ if .Desc.HasOptionalKeyword }} (optional){{ end }} | 115 | {{- if (or (is_primitive .) (is_google_type .)) -}} 116 | {{ field_type . }} 117 | {{- else -}} 118 | [{{ .| field_type }}]({{ type_link . }}) 119 | {{- end -}} 120 | | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr }} | 121 | {{end}} 122 | 123 | {{/*************************************************************** 124 | Oneof template 125 | This is kind of gross since GFM doesn't support colspan. 126 | ***************************************************************/}} 127 | {{define "oneof" -}} 128 | |Union field `{{ .Desc.Name }}`. {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr }} `{{ .Desc.Name }}` can be only one of the following:| 129 | {{range .Fields}}{{template "field" .}}{{end}} 130 | {{end}} 131 | 132 | {{/*************************************************************** 133 | Enum template 134 | ***************************************************************/}} 135 | {{define "enum" }} 136 | 137 | 138 | ### {{.Desc | long_name}} 139 | {{.Comments.Leading | description}} 140 | {{.Comments.Trailing | description}} 141 | 142 | | Name | Number | Description | 143 | | ---- | ------ | ----------- | 144 | {{range .Values -}} 145 | | {{.Desc.Name}} | {{.Desc.Number}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | 146 | {{end}} 147 | {{end}} 148 | -------------------------------------------------------------------------------- /testdata/example1/booking.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: com.example.booking 3 | description: API Specification for the com.example.booking package. 4 | --- 5 | 6 |

Top

7 | 8 | 9 | 10 | 11 | 12 | 13 | ### BookingService 14 | 15 | Service for handling vehicle bookings. 16 | 17 | 18 | 19 | | Method Name | Request Type | Response Type | Description | 20 | | ----------- | ------------ | ------------- | ------------| 21 | | BookVehicle | [Booking](#com-example-booking-Booking) | [BookingStatus](#com-example-booking-BookingStatus) | Used to book a vehicle. Pass in a Booking and a BookingStatus will be returned. | 22 | | BookingUpdates | [BookingStatusID](#com-example-booking-BookingStatusID) | [BookingStatus](#com-example-booking-BookingStatus) stream | Used to subscribe to updates of the BookingStatus. | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ### BookingStatusID 33 | 34 | Represents the booking status ID. 35 | 36 | 37 | 38 | 39 | | Field | Type | Description | 40 | | ----- | ---- | ----------- | 41 | | id |int32| Unique booking status ID. | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | ### BookingStatus 56 | 57 | Represents the status of a vehicle booking. 58 | 59 | 60 | 61 | 62 | | Field | Type | Description | 63 | | ----- | ---- | ----------- | 64 | | id |int32| Unique booking status ID. | 65 | | description |string| Booking status description. E.g. "Active". | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | ### Booking 80 | 81 | Represents the booking of a vehicle. 82 | 83 | Vehicles are quite fun. But drive carefully! 84 | 85 | 86 | 87 | 88 | | Field | Type | Description | 89 | | ----- | ---- | ----------- | 90 | | vehicle_id |int32| ID of booked vehicle. | 91 | | customer_id |int32| Customer that booked the vehicle. | 92 | | status |[BookingStatus](#com-example-booking-BookingStatus)| Status of the booking. | 93 | | confirmation_sent |bool| Has booking confirmation been sent? | 94 | | payment_received |bool| Has payment been received? | 95 | | color_preference |string| Color preference of the customer. | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | ### EmptyBookingMessage 110 | 111 | An empty message for testing 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /testdata/example1/booking.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Booking related messages. 3 | * 4 | * This file is really just an example. The data model is completely 5 | * fictional. 6 | */ 7 | syntax = "proto3"; 8 | 9 | option go_package = "example.com/booking"; 10 | 11 | package com.example.booking; 12 | 13 | /** 14 | * Represents the booking status ID. 15 | */ 16 | message BookingStatusID { 17 | int32 id = 1; /// Unique booking status ID. 18 | } 19 | 20 | /** 21 | * Represents the status of a vehicle booking. 22 | */ 23 | message BookingStatus { 24 | int32 id = 1; /// Unique booking status ID. 25 | string description = 2; /// Booking status description. E.g. "Active". 26 | } 27 | 28 | /** 29 | * Represents the booking of a vehicle. 30 | * 31 | * Vehicles are quite fun. But drive carefully! 32 | */ 33 | message Booking { 34 | int32 vehicle_id = 1; /// ID of booked vehicle. 35 | int32 customer_id = 2; /// Customer that booked the vehicle. 36 | BookingStatus status = 3; /// Status of the booking. 37 | 38 | /** Has booking confirmation been sent? */ 39 | bool confirmation_sent = 4; 40 | 41 | /** Has payment been received? */ 42 | bool payment_received = 5; 43 | 44 | string color_preference = 6 [deprecated=true]; // Color preference of the customer. 45 | } 46 | 47 | // An empty message for testing 48 | message EmptyBookingMessage { 49 | } 50 | 51 | /** 52 | * Service for handling vehicle bookings. 53 | */ 54 | service BookingService { 55 | /// Used to book a vehicle. Pass in a Booking and a BookingStatus will be returned. 56 | rpc BookVehicle (Booking) returns (BookingStatus) {} 57 | 58 | /// Used to subscribe to updates of the BookingStatus. 59 | rpc BookingUpdates (BookingStatusID) returns (stream BookingStatus); 60 | } 61 | -------------------------------------------------------------------------------- /testdata/example1/field_presence.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: com.example.proto3 3 | description: API Specification for the com.example.proto3 package. 4 | --- 5 | 6 |

Top

7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ### MyMessage 17 | 18 | 19 | 20 | 21 | 22 | | Field | Type | Description | 23 | | ----- | ---- | ----------- | 24 | | not_tracked |int32| | 25 | | tracked (optional) |int32| Explicit presence | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | ### AnotherMessage 40 | 41 | 42 | 43 | 44 | 45 | | Field | Type | Description | 46 | | ----- | ---- | ----------- | 47 | | id |int32| | 48 | |Union field `payload`. `payload` can be only one of the following:| 49 | | my_message |[MyMessage](#com-example-proto3-MyMessage)| | 50 | | my_string |string| | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /testdata/example1/field_presence.proto: -------------------------------------------------------------------------------- 1 | // Encoding and show field presence. 2 | syntax = "proto3"; 3 | 4 | package com.example.proto3; 5 | 6 | option go_package = "example.com/vehicleproto3"; 7 | 8 | message MyMessage { 9 | int32 not_tracked = 1; 10 | // Explicit presence 11 | optional int32 tracked = 2; 12 | } 13 | 14 | message AnotherMessage { 15 | int32 id = 1; 16 | oneof payload { 17 | MyMessage my_message = 2; 18 | string my_string = 3; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /testdata/example1/vehicle.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: com.example 3 | description: API Specification for the com.example package. 4 | --- 5 | 6 |

Top

7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ### Manufacturer 17 | 18 | Represents a manufacturer of cars. 19 | 20 | 21 | 22 | 23 | | Field | Type | Description | 24 | | ----- | ---- | ----------- | 25 | | id |int32| The unique manufacturer ID. | 26 | | code |string| A manufacturer code, e.g. "DKL4P". | 27 | | details (optional) |string| Manufacturer details (minimum orders et.c.). | 28 | | category (optional) |[Manufacturer.Category](#com-example-Manufacturer-Category)| Manufacturer category. | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | ### Manufacturer.Category 40 | Manufacturer category. A manufacturer may be either inhouse or external. 41 | 42 | 43 | 44 | | Name | Number | Description | 45 | | ---- | ------ | ----------- | 46 | | CATEGORY_INHOUSE | 0 | The manufacturer is inhouse. | 47 | | CATEGORY_EXTERNAL | 1 | The manufacturer is external. | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | ### Model 58 | 59 | Represents a vehicle model. 60 | 61 | 62 | 63 | 64 | | Field | Type | Description | 65 | | ----- | ---- | ----------- | 66 | | id |string| The unique model ID. | 67 | | model_code |string| The car model code, e.g. "PZ003". | 68 | | model_name |string| The car model name, e.g. "Z3". | 69 | | daily_hire_rate_dollars |sint32| Dollars per day. | 70 | | daily_hire_rate_cents |sint32| Cents per day. | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | ### Vehicle 85 | 86 | Represents a vehicle that can be hired. 87 | 88 | 89 | 90 | 91 | | Field | Type | Description | 92 | | ----- | ---- | ----------- | 93 | | id |int32| Unique vehicle ID. | 94 | | model |[Model](#com-example-Model)| Vehicle model. | 95 | | reg_number |string| Vehicle registration number. | 96 | | mileage (optional) |sint32| Current vehicle mileage, if known. | 97 | | category (optional) |[Vehicle.Category](#com-example-Vehicle-Category)| Vehicle category. | 98 | | daily_hire_rate_dollars (optional) |sint32| Dollars per day. | 99 | | daily_hire_rate_cents (optional) |sint32| Cents per day. | 100 | 101 | 102 | 103 | | Extension | Type | Base | Number | Description | 104 | | --------- | ---- | ---- | ------ | ----------- | 105 | | series | Vehicle.series | Vehicle | 100 | Vehicle model series. | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | ### Category 114 | 115 | Represents a vehicle category. E.g. "Sedan" or "Truck". 116 | 117 | 118 | 119 | 120 | | Field | Type | Description | 121 | | ----- | ---- | ----------- | 122 | | code |string| Category code. E.g. "S". | 123 | | description |string| Category name. E.g. "Sedan". | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | ### Coolness 146 | 147 | 148 | 149 | | Name | Number | Description | 150 | | ---- | ------ | ----------- | 151 | | COOLNESS_UNSPECIFIED | 0 | The coolness is unknown. | 152 | | COOLNESS_MAX | 1 | The coolness is maximum. | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | ### Extensions 162 | | Extension | Type | Extension Point | Number | Description | 163 | | --------- | ---- | ---- | ------ | ----------- | 164 | | country | com.example.country | Manufacturer | 100 | Manufacturer country. | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /testdata/example1/vehicle.proto: -------------------------------------------------------------------------------- 1 | /** Messages describing manufacturers / vehicles. */ 2 | syntax = "proto2"; 3 | 4 | package com.example; 5 | 6 | option go_package = "example.com/vehicle"; 7 | 8 | enum Coolness { 9 | COOLNESS_UNSPECIFIED = 0; /** The coolness is unknown. */ 10 | COOLNESS_MAX = 1; /** The coolness is maximum. */ 11 | } 12 | 13 | /** 14 | * Represents a manufacturer of cars. 15 | */ 16 | message Manufacturer { 17 | /** 18 | * Manufacturer category. A manufacturer may be either inhouse or external. 19 | */ 20 | enum Category { 21 | CATEGORY_INHOUSE = 0; /** The manufacturer is inhouse. */ 22 | CATEGORY_EXTERNAL = 1; /** The manufacturer is external. */ 23 | } 24 | 25 | required int32 id = 1; /** The unique manufacturer ID. */ 26 | required string code = 2; /** A manufacturer code, e.g. "DKL4P". */ 27 | optional string details = 3; /** Manufacturer details (minimum orders et.c.). */ 28 | 29 | /** Manufacturer category. */ 30 | optional Category category = 4 [default = CATEGORY_EXTERNAL]; 31 | 32 | extensions 100 to max; 33 | } 34 | 35 | // File-level extensions can also be documented: 36 | 37 | extend Manufacturer { 38 | /** Manufacturer country. */ 39 | optional string country = 100 [default = "China"]; 40 | } 41 | 42 | /** 43 | * Represents a vehicle model. 44 | */ 45 | message Model { 46 | required string id = 1; /** The unique model ID. */ 47 | required string model_code = 2; /** The car model code, e.g. "PZ003". */ 48 | required string model_name = 3; /** The car model name, e.g. "Z3". */ 49 | 50 | required sint32 daily_hire_rate_dollars = 4; /// Dollars per day. 51 | required sint32 daily_hire_rate_cents = 5; /// Cents per day. 52 | 53 | extensions 100 to max; 54 | } 55 | 56 | /** 57 | * Represents a vehicle that can be hired. 58 | */ 59 | message Vehicle { 60 | /** 61 | * Represents a vehicle category. E.g. "Sedan" or "Truck". 62 | */ 63 | message Category { 64 | required string code = 1; /// Category code. E.g. "S". 65 | required string description = 2; /// Category name. E.g. "Sedan". 66 | } 67 | 68 | required int32 id = 1; /** Unique vehicle ID. */ 69 | required Model model = 2; /** Vehicle model. */ 70 | required string reg_number = 3; /** Vehicle registration number. */ 71 | optional sint32 mileage = 4; /** Current vehicle mileage, if known. */ 72 | optional Category category = 5; /** Vehicle category. */ 73 | 74 | // Doc comments for fields can come before or 75 | // after the field definition. And just like 76 | // comments for messages / enums, they can be 77 | // multi-paragraph: 78 | 79 | /** 80 | * Dollars per day. 81 | */ 82 | optional sint32 daily_hire_rate_dollars = 6 [default = 50]; 83 | 84 | /** 85 | * Cents per day. 86 | */ 87 | optional sint32 daily_hire_rate_cents = 7; 88 | 89 | // Nested extensions can also be documented: 90 | 91 | extend Model { 92 | /** Vehicle model series. */ 93 | optional string series = 100; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /thirdparty/generate.go: -------------------------------------------------------------------------------- 1 | package thirdparty 2 | 3 | //go:generate mkdir -p github.com/envoyproxy/protoc-gen-validate/validate 4 | //go:generate curl -fsSL https://github.com/envoyproxy/protoc-gen-validate/raw/main/validate/validate.proto -o github.com/envoyproxy/protoc-gen-validate/validate/validate.proto 5 | 6 | //go:generate mkdir -p github.com/mwitkow/go-proto-validators 7 | //go:generate curl -fsSL https://github.com/mwitkow/go-proto-validators/raw/master/validator.proto -o github.com/mwitkow/go-proto-validators/validator.proto 8 | 9 | //go:generate mkdir -p github.com/pseudomuto/protokit/fixtures 10 | //go:generate curl -fsSL https://github.com/pseudomuto/protokit/raw/master/fixtures/extend.proto -o github.com/pseudomuto/protokit/fixtures/extend.proto 11 | -------------------------------------------------------------------------------- /thirdparty/github.com/envoyproxy/protoc-gen-validate/validate/validate.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | package validate; 3 | 4 | option go_package = "github.com/envoyproxy/protoc-gen-validate/validate"; 5 | option java_package = "io.envoyproxy.pgv.validate"; 6 | 7 | import "google/protobuf/descriptor.proto"; 8 | import "google/protobuf/duration.proto"; 9 | import "google/protobuf/timestamp.proto"; 10 | 11 | // Validation rules applied at the message level 12 | extend google.protobuf.MessageOptions { 13 | // Disabled nullifies any validation rules for this message, including any 14 | // message fields associated with it that do support validation. 15 | optional bool disabled = 1071; 16 | // Ignore skips generation of validation methods for this message. 17 | optional bool ignored = 1072; 18 | } 19 | 20 | // Validation rules applied at the oneof level 21 | extend google.protobuf.OneofOptions { 22 | // Required ensures that exactly one the field options in a oneof is set; 23 | // validation fails if no fields in the oneof are set. 24 | optional bool required = 1071; 25 | } 26 | 27 | // Validation rules applied at the field level 28 | extend google.protobuf.FieldOptions { 29 | // Rules specify the validations to be performed on this field. By default, 30 | // no validation is performed against a field. 31 | optional FieldRules rules = 1071; 32 | } 33 | 34 | // FieldRules encapsulates the rules for each type of field. Depending on the 35 | // field, the correct set should be used to ensure proper validations. 36 | message FieldRules { 37 | optional MessageRules message = 17; 38 | oneof type { 39 | // Scalar Field Types 40 | FloatRules float = 1; 41 | DoubleRules double = 2; 42 | Int32Rules int32 = 3; 43 | Int64Rules int64 = 4; 44 | UInt32Rules uint32 = 5; 45 | UInt64Rules uint64 = 6; 46 | SInt32Rules sint32 = 7; 47 | SInt64Rules sint64 = 8; 48 | Fixed32Rules fixed32 = 9; 49 | Fixed64Rules fixed64 = 10; 50 | SFixed32Rules sfixed32 = 11; 51 | SFixed64Rules sfixed64 = 12; 52 | BoolRules bool = 13; 53 | StringRules string = 14; 54 | BytesRules bytes = 15; 55 | 56 | // Complex Field Types 57 | EnumRules enum = 16; 58 | RepeatedRules repeated = 18; 59 | MapRules map = 19; 60 | 61 | // Well-Known Field Types 62 | AnyRules any = 20; 63 | DurationRules duration = 21; 64 | TimestampRules timestamp = 22; 65 | } 66 | } 67 | 68 | // FloatRules describes the constraints applied to `float` values 69 | message FloatRules { 70 | // Const specifies that this field must be exactly the specified value 71 | optional float const = 1; 72 | 73 | // Lt specifies that this field must be less than the specified value, 74 | // exclusive 75 | optional float lt = 2; 76 | 77 | // Lte specifies that this field must be less than or equal to the 78 | // specified value, inclusive 79 | optional float lte = 3; 80 | 81 | // Gt specifies that this field must be greater than the specified value, 82 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 83 | // range is reversed. 84 | optional float gt = 4; 85 | 86 | // Gte specifies that this field must be greater than or equal to the 87 | // specified value, inclusive. If the value of Gte is larger than a 88 | // specified Lt or Lte, the range is reversed. 89 | optional float gte = 5; 90 | 91 | // In specifies that this field must be equal to one of the specified 92 | // values 93 | repeated float in = 6; 94 | 95 | // NotIn specifies that this field cannot be equal to one of the specified 96 | // values 97 | repeated float not_in = 7; 98 | 99 | // IgnoreEmpty specifies that the validation rules of this field should be 100 | // evaluated only if the field is not empty 101 | optional bool ignore_empty = 8; 102 | } 103 | 104 | // DoubleRules describes the constraints applied to `double` values 105 | message DoubleRules { 106 | // Const specifies that this field must be exactly the specified value 107 | optional double const = 1; 108 | 109 | // Lt specifies that this field must be less than the specified value, 110 | // exclusive 111 | optional double lt = 2; 112 | 113 | // Lte specifies that this field must be less than or equal to the 114 | // specified value, inclusive 115 | optional double lte = 3; 116 | 117 | // Gt specifies that this field must be greater than the specified value, 118 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 119 | // range is reversed. 120 | optional double gt = 4; 121 | 122 | // Gte specifies that this field must be greater than or equal to the 123 | // specified value, inclusive. If the value of Gte is larger than a 124 | // specified Lt or Lte, the range is reversed. 125 | optional double gte = 5; 126 | 127 | // In specifies that this field must be equal to one of the specified 128 | // values 129 | repeated double in = 6; 130 | 131 | // NotIn specifies that this field cannot be equal to one of the specified 132 | // values 133 | repeated double not_in = 7; 134 | 135 | // IgnoreEmpty specifies that the validation rules of this field should be 136 | // evaluated only if the field is not empty 137 | optional bool ignore_empty = 8; 138 | } 139 | 140 | // Int32Rules describes the constraints applied to `int32` values 141 | message Int32Rules { 142 | // Const specifies that this field must be exactly the specified value 143 | optional int32 const = 1; 144 | 145 | // Lt specifies that this field must be less than the specified value, 146 | // exclusive 147 | optional int32 lt = 2; 148 | 149 | // Lte specifies that this field must be less than or equal to the 150 | // specified value, inclusive 151 | optional int32 lte = 3; 152 | 153 | // Gt specifies that this field must be greater than the specified value, 154 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 155 | // range is reversed. 156 | optional int32 gt = 4; 157 | 158 | // Gte specifies that this field must be greater than or equal to the 159 | // specified value, inclusive. If the value of Gte is larger than a 160 | // specified Lt or Lte, the range is reversed. 161 | optional int32 gte = 5; 162 | 163 | // In specifies that this field must be equal to one of the specified 164 | // values 165 | repeated int32 in = 6; 166 | 167 | // NotIn specifies that this field cannot be equal to one of the specified 168 | // values 169 | repeated int32 not_in = 7; 170 | 171 | // IgnoreEmpty specifies that the validation rules of this field should be 172 | // evaluated only if the field is not empty 173 | optional bool ignore_empty = 8; 174 | } 175 | 176 | // Int64Rules describes the constraints applied to `int64` values 177 | message Int64Rules { 178 | // Const specifies that this field must be exactly the specified value 179 | optional int64 const = 1; 180 | 181 | // Lt specifies that this field must be less than the specified value, 182 | // exclusive 183 | optional int64 lt = 2; 184 | 185 | // Lte specifies that this field must be less than or equal to the 186 | // specified value, inclusive 187 | optional int64 lte = 3; 188 | 189 | // Gt specifies that this field must be greater than the specified value, 190 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 191 | // range is reversed. 192 | optional int64 gt = 4; 193 | 194 | // Gte specifies that this field must be greater than or equal to the 195 | // specified value, inclusive. If the value of Gte is larger than a 196 | // specified Lt or Lte, the range is reversed. 197 | optional int64 gte = 5; 198 | 199 | // In specifies that this field must be equal to one of the specified 200 | // values 201 | repeated int64 in = 6; 202 | 203 | // NotIn specifies that this field cannot be equal to one of the specified 204 | // values 205 | repeated int64 not_in = 7; 206 | 207 | // IgnoreEmpty specifies that the validation rules of this field should be 208 | // evaluated only if the field is not empty 209 | optional bool ignore_empty = 8; 210 | } 211 | 212 | // UInt32Rules describes the constraints applied to `uint32` values 213 | message UInt32Rules { 214 | // Const specifies that this field must be exactly the specified value 215 | optional uint32 const = 1; 216 | 217 | // Lt specifies that this field must be less than the specified value, 218 | // exclusive 219 | optional uint32 lt = 2; 220 | 221 | // Lte specifies that this field must be less than or equal to the 222 | // specified value, inclusive 223 | optional uint32 lte = 3; 224 | 225 | // Gt specifies that this field must be greater than the specified value, 226 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 227 | // range is reversed. 228 | optional uint32 gt = 4; 229 | 230 | // Gte specifies that this field must be greater than or equal to the 231 | // specified value, inclusive. If the value of Gte is larger than a 232 | // specified Lt or Lte, the range is reversed. 233 | optional uint32 gte = 5; 234 | 235 | // In specifies that this field must be equal to one of the specified 236 | // values 237 | repeated uint32 in = 6; 238 | 239 | // NotIn specifies that this field cannot be equal to one of the specified 240 | // values 241 | repeated uint32 not_in = 7; 242 | 243 | // IgnoreEmpty specifies that the validation rules of this field should be 244 | // evaluated only if the field is not empty 245 | optional bool ignore_empty = 8; 246 | } 247 | 248 | // UInt64Rules describes the constraints applied to `uint64` values 249 | message UInt64Rules { 250 | // Const specifies that this field must be exactly the specified value 251 | optional uint64 const = 1; 252 | 253 | // Lt specifies that this field must be less than the specified value, 254 | // exclusive 255 | optional uint64 lt = 2; 256 | 257 | // Lte specifies that this field must be less than or equal to the 258 | // specified value, inclusive 259 | optional uint64 lte = 3; 260 | 261 | // Gt specifies that this field must be greater than the specified value, 262 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 263 | // range is reversed. 264 | optional uint64 gt = 4; 265 | 266 | // Gte specifies that this field must be greater than or equal to the 267 | // specified value, inclusive. If the value of Gte is larger than a 268 | // specified Lt or Lte, the range is reversed. 269 | optional uint64 gte = 5; 270 | 271 | // In specifies that this field must be equal to one of the specified 272 | // values 273 | repeated uint64 in = 6; 274 | 275 | // NotIn specifies that this field cannot be equal to one of the specified 276 | // values 277 | repeated uint64 not_in = 7; 278 | 279 | // IgnoreEmpty specifies that the validation rules of this field should be 280 | // evaluated only if the field is not empty 281 | optional bool ignore_empty = 8; 282 | } 283 | 284 | // SInt32Rules describes the constraints applied to `sint32` values 285 | message SInt32Rules { 286 | // Const specifies that this field must be exactly the specified value 287 | optional sint32 const = 1; 288 | 289 | // Lt specifies that this field must be less than the specified value, 290 | // exclusive 291 | optional sint32 lt = 2; 292 | 293 | // Lte specifies that this field must be less than or equal to the 294 | // specified value, inclusive 295 | optional sint32 lte = 3; 296 | 297 | // Gt specifies that this field must be greater than the specified value, 298 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 299 | // range is reversed. 300 | optional sint32 gt = 4; 301 | 302 | // Gte specifies that this field must be greater than or equal to the 303 | // specified value, inclusive. If the value of Gte is larger than a 304 | // specified Lt or Lte, the range is reversed. 305 | optional sint32 gte = 5; 306 | 307 | // In specifies that this field must be equal to one of the specified 308 | // values 309 | repeated sint32 in = 6; 310 | 311 | // NotIn specifies that this field cannot be equal to one of the specified 312 | // values 313 | repeated sint32 not_in = 7; 314 | 315 | // IgnoreEmpty specifies that the validation rules of this field should be 316 | // evaluated only if the field is not empty 317 | optional bool ignore_empty = 8; 318 | } 319 | 320 | // SInt64Rules describes the constraints applied to `sint64` values 321 | message SInt64Rules { 322 | // Const specifies that this field must be exactly the specified value 323 | optional sint64 const = 1; 324 | 325 | // Lt specifies that this field must be less than the specified value, 326 | // exclusive 327 | optional sint64 lt = 2; 328 | 329 | // Lte specifies that this field must be less than or equal to the 330 | // specified value, inclusive 331 | optional sint64 lte = 3; 332 | 333 | // Gt specifies that this field must be greater than the specified value, 334 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 335 | // range is reversed. 336 | optional sint64 gt = 4; 337 | 338 | // Gte specifies that this field must be greater than or equal to the 339 | // specified value, inclusive. If the value of Gte is larger than a 340 | // specified Lt or Lte, the range is reversed. 341 | optional sint64 gte = 5; 342 | 343 | // In specifies that this field must be equal to one of the specified 344 | // values 345 | repeated sint64 in = 6; 346 | 347 | // NotIn specifies that this field cannot be equal to one of the specified 348 | // values 349 | repeated sint64 not_in = 7; 350 | 351 | // IgnoreEmpty specifies that the validation rules of this field should be 352 | // evaluated only if the field is not empty 353 | optional bool ignore_empty = 8; 354 | } 355 | 356 | // Fixed32Rules describes the constraints applied to `fixed32` values 357 | message Fixed32Rules { 358 | // Const specifies that this field must be exactly the specified value 359 | optional fixed32 const = 1; 360 | 361 | // Lt specifies that this field must be less than the specified value, 362 | // exclusive 363 | optional fixed32 lt = 2; 364 | 365 | // Lte specifies that this field must be less than or equal to the 366 | // specified value, inclusive 367 | optional fixed32 lte = 3; 368 | 369 | // Gt specifies that this field must be greater than the specified value, 370 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 371 | // range is reversed. 372 | optional fixed32 gt = 4; 373 | 374 | // Gte specifies that this field must be greater than or equal to the 375 | // specified value, inclusive. If the value of Gte is larger than a 376 | // specified Lt or Lte, the range is reversed. 377 | optional fixed32 gte = 5; 378 | 379 | // In specifies that this field must be equal to one of the specified 380 | // values 381 | repeated fixed32 in = 6; 382 | 383 | // NotIn specifies that this field cannot be equal to one of the specified 384 | // values 385 | repeated fixed32 not_in = 7; 386 | 387 | // IgnoreEmpty specifies that the validation rules of this field should be 388 | // evaluated only if the field is not empty 389 | optional bool ignore_empty = 8; 390 | } 391 | 392 | // Fixed64Rules describes the constraints applied to `fixed64` values 393 | message Fixed64Rules { 394 | // Const specifies that this field must be exactly the specified value 395 | optional fixed64 const = 1; 396 | 397 | // Lt specifies that this field must be less than the specified value, 398 | // exclusive 399 | optional fixed64 lt = 2; 400 | 401 | // Lte specifies that this field must be less than or equal to the 402 | // specified value, inclusive 403 | optional fixed64 lte = 3; 404 | 405 | // Gt specifies that this field must be greater than the specified value, 406 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 407 | // range is reversed. 408 | optional fixed64 gt = 4; 409 | 410 | // Gte specifies that this field must be greater than or equal to the 411 | // specified value, inclusive. If the value of Gte is larger than a 412 | // specified Lt or Lte, the range is reversed. 413 | optional fixed64 gte = 5; 414 | 415 | // In specifies that this field must be equal to one of the specified 416 | // values 417 | repeated fixed64 in = 6; 418 | 419 | // NotIn specifies that this field cannot be equal to one of the specified 420 | // values 421 | repeated fixed64 not_in = 7; 422 | 423 | // IgnoreEmpty specifies that the validation rules of this field should be 424 | // evaluated only if the field is not empty 425 | optional bool ignore_empty = 8; 426 | } 427 | 428 | // SFixed32Rules describes the constraints applied to `sfixed32` values 429 | message SFixed32Rules { 430 | // Const specifies that this field must be exactly the specified value 431 | optional sfixed32 const = 1; 432 | 433 | // Lt specifies that this field must be less than the specified value, 434 | // exclusive 435 | optional sfixed32 lt = 2; 436 | 437 | // Lte specifies that this field must be less than or equal to the 438 | // specified value, inclusive 439 | optional sfixed32 lte = 3; 440 | 441 | // Gt specifies that this field must be greater than the specified value, 442 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 443 | // range is reversed. 444 | optional sfixed32 gt = 4; 445 | 446 | // Gte specifies that this field must be greater than or equal to the 447 | // specified value, inclusive. If the value of Gte is larger than a 448 | // specified Lt or Lte, the range is reversed. 449 | optional sfixed32 gte = 5; 450 | 451 | // In specifies that this field must be equal to one of the specified 452 | // values 453 | repeated sfixed32 in = 6; 454 | 455 | // NotIn specifies that this field cannot be equal to one of the specified 456 | // values 457 | repeated sfixed32 not_in = 7; 458 | 459 | // IgnoreEmpty specifies that the validation rules of this field should be 460 | // evaluated only if the field is not empty 461 | optional bool ignore_empty = 8; 462 | } 463 | 464 | // SFixed64Rules describes the constraints applied to `sfixed64` values 465 | message SFixed64Rules { 466 | // Const specifies that this field must be exactly the specified value 467 | optional sfixed64 const = 1; 468 | 469 | // Lt specifies that this field must be less than the specified value, 470 | // exclusive 471 | optional sfixed64 lt = 2; 472 | 473 | // Lte specifies that this field must be less than or equal to the 474 | // specified value, inclusive 475 | optional sfixed64 lte = 3; 476 | 477 | // Gt specifies that this field must be greater than the specified value, 478 | // exclusive. If the value of Gt is larger than a specified Lt or Lte, the 479 | // range is reversed. 480 | optional sfixed64 gt = 4; 481 | 482 | // Gte specifies that this field must be greater than or equal to the 483 | // specified value, inclusive. If the value of Gte is larger than a 484 | // specified Lt or Lte, the range is reversed. 485 | optional sfixed64 gte = 5; 486 | 487 | // In specifies that this field must be equal to one of the specified 488 | // values 489 | repeated sfixed64 in = 6; 490 | 491 | // NotIn specifies that this field cannot be equal to one of the specified 492 | // values 493 | repeated sfixed64 not_in = 7; 494 | 495 | // IgnoreEmpty specifies that the validation rules of this field should be 496 | // evaluated only if the field is not empty 497 | optional bool ignore_empty = 8; 498 | } 499 | 500 | // BoolRules describes the constraints applied to `bool` values 501 | message BoolRules { 502 | // Const specifies that this field must be exactly the specified value 503 | optional bool const = 1; 504 | } 505 | 506 | // StringRules describe the constraints applied to `string` values 507 | message StringRules { 508 | // Const specifies that this field must be exactly the specified value 509 | optional string const = 1; 510 | 511 | // Len specifies that this field must be the specified number of 512 | // characters (Unicode code points). Note that the number of 513 | // characters may differ from the number of bytes in the string. 514 | optional uint64 len = 19; 515 | 516 | // MinLen specifies that this field must be the specified number of 517 | // characters (Unicode code points) at a minimum. Note that the number of 518 | // characters may differ from the number of bytes in the string. 519 | optional uint64 min_len = 2; 520 | 521 | // MaxLen specifies that this field must be the specified number of 522 | // characters (Unicode code points) at a maximum. Note that the number of 523 | // characters may differ from the number of bytes in the string. 524 | optional uint64 max_len = 3; 525 | 526 | // LenBytes specifies that this field must be the specified number of bytes 527 | optional uint64 len_bytes = 20; 528 | 529 | // MinBytes specifies that this field must be the specified number of bytes 530 | // at a minimum 531 | optional uint64 min_bytes = 4; 532 | 533 | // MaxBytes specifies that this field must be the specified number of bytes 534 | // at a maximum 535 | optional uint64 max_bytes = 5; 536 | 537 | // Pattern specifes that this field must match against the specified 538 | // regular expression (RE2 syntax). The included expression should elide 539 | // any delimiters. 540 | optional string pattern = 6; 541 | 542 | // Prefix specifies that this field must have the specified substring at 543 | // the beginning of the string. 544 | optional string prefix = 7; 545 | 546 | // Suffix specifies that this field must have the specified substring at 547 | // the end of the string. 548 | optional string suffix = 8; 549 | 550 | // Contains specifies that this field must have the specified substring 551 | // anywhere in the string. 552 | optional string contains = 9; 553 | 554 | // NotContains specifies that this field cannot have the specified substring 555 | // anywhere in the string. 556 | optional string not_contains = 23; 557 | 558 | // In specifies that this field must be equal to one of the specified 559 | // values 560 | repeated string in = 10; 561 | 562 | // NotIn specifies that this field cannot be equal to one of the specified 563 | // values 564 | repeated string not_in = 11; 565 | 566 | // WellKnown rules provide advanced constraints against common string 567 | // patterns 568 | oneof well_known { 569 | // Email specifies that the field must be a valid email address as 570 | // defined by RFC 5322 571 | bool email = 12; 572 | 573 | // Hostname specifies that the field must be a valid hostname as 574 | // defined by RFC 1034. This constraint does not support 575 | // internationalized domain names (IDNs). 576 | bool hostname = 13; 577 | 578 | // Ip specifies that the field must be a valid IP (v4 or v6) address. 579 | // Valid IPv6 addresses should not include surrounding square brackets. 580 | bool ip = 14; 581 | 582 | // Ipv4 specifies that the field must be a valid IPv4 address. 583 | bool ipv4 = 15; 584 | 585 | // Ipv6 specifies that the field must be a valid IPv6 address. Valid 586 | // IPv6 addresses should not include surrounding square brackets. 587 | bool ipv6 = 16; 588 | 589 | // Uri specifies that the field must be a valid, absolute URI as defined 590 | // by RFC 3986 591 | bool uri = 17; 592 | 593 | // UriRef specifies that the field must be a valid URI as defined by RFC 594 | // 3986 and may be relative or absolute. 595 | bool uri_ref = 18; 596 | 597 | // Address specifies that the field must be either a valid hostname as 598 | // defined by RFC 1034 (which does not support internationalized domain 599 | // names or IDNs), or it can be a valid IP (v4 or v6). 600 | bool address = 21; 601 | 602 | // Uuid specifies that the field must be a valid UUID as defined by 603 | // RFC 4122 604 | bool uuid = 22; 605 | 606 | // WellKnownRegex specifies a common well known pattern defined as a regex. 607 | KnownRegex well_known_regex = 24; 608 | } 609 | 610 | // This applies to regexes HTTP_HEADER_NAME and HTTP_HEADER_VALUE to enable 611 | // strict header validation. 612 | // By default, this is true, and HTTP header validations are RFC-compliant. 613 | // Setting to false will enable a looser validations that only disallows 614 | // \r\n\0 characters, which can be used to bypass header matching rules. 615 | optional bool strict = 25 [default = true]; 616 | 617 | // IgnoreEmpty specifies that the validation rules of this field should be 618 | // evaluated only if the field is not empty 619 | optional bool ignore_empty = 26; 620 | } 621 | 622 | // WellKnownRegex contain some well-known patterns. 623 | enum KnownRegex { 624 | UNKNOWN = 0; 625 | 626 | // HTTP header name as defined by RFC 7230. 627 | HTTP_HEADER_NAME = 1; 628 | 629 | // HTTP header value as defined by RFC 7230. 630 | HTTP_HEADER_VALUE = 2; 631 | } 632 | 633 | // BytesRules describe the constraints applied to `bytes` values 634 | message BytesRules { 635 | // Const specifies that this field must be exactly the specified value 636 | optional bytes const = 1; 637 | 638 | // Len specifies that this field must be the specified number of bytes 639 | optional uint64 len = 13; 640 | 641 | // MinLen specifies that this field must be the specified number of bytes 642 | // at a minimum 643 | optional uint64 min_len = 2; 644 | 645 | // MaxLen specifies that this field must be the specified number of bytes 646 | // at a maximum 647 | optional uint64 max_len = 3; 648 | 649 | // Pattern specifes that this field must match against the specified 650 | // regular expression (RE2 syntax). The included expression should elide 651 | // any delimiters. 652 | optional string pattern = 4; 653 | 654 | // Prefix specifies that this field must have the specified bytes at the 655 | // beginning of the string. 656 | optional bytes prefix = 5; 657 | 658 | // Suffix specifies that this field must have the specified bytes at the 659 | // end of the string. 660 | optional bytes suffix = 6; 661 | 662 | // Contains specifies that this field must have the specified bytes 663 | // anywhere in the string. 664 | optional bytes contains = 7; 665 | 666 | // In specifies that this field must be equal to one of the specified 667 | // values 668 | repeated bytes in = 8; 669 | 670 | // NotIn specifies that this field cannot be equal to one of the specified 671 | // values 672 | repeated bytes not_in = 9; 673 | 674 | // WellKnown rules provide advanced constraints against common byte 675 | // patterns 676 | oneof well_known { 677 | // Ip specifies that the field must be a valid IP (v4 or v6) address in 678 | // byte format 679 | bool ip = 10; 680 | 681 | // Ipv4 specifies that the field must be a valid IPv4 address in byte 682 | // format 683 | bool ipv4 = 11; 684 | 685 | // Ipv6 specifies that the field must be a valid IPv6 address in byte 686 | // format 687 | bool ipv6 = 12; 688 | } 689 | 690 | // IgnoreEmpty specifies that the validation rules of this field should be 691 | // evaluated only if the field is not empty 692 | optional bool ignore_empty = 14; 693 | } 694 | 695 | // EnumRules describe the constraints applied to enum values 696 | message EnumRules { 697 | // Const specifies that this field must be exactly the specified value 698 | optional int32 const = 1; 699 | 700 | // DefinedOnly specifies that this field must be only one of the defined 701 | // values for this enum, failing on any undefined value. 702 | optional bool defined_only = 2; 703 | 704 | // In specifies that this field must be equal to one of the specified 705 | // values 706 | repeated int32 in = 3; 707 | 708 | // NotIn specifies that this field cannot be equal to one of the specified 709 | // values 710 | repeated int32 not_in = 4; 711 | } 712 | 713 | // MessageRules describe the constraints applied to embedded message values. 714 | // For message-type fields, validation is performed recursively. 715 | message MessageRules { 716 | // Skip specifies that the validation rules of this field should not be 717 | // evaluated 718 | optional bool skip = 1; 719 | 720 | // Required specifies that this field must be set 721 | optional bool required = 2; 722 | } 723 | 724 | // RepeatedRules describe the constraints applied to `repeated` values 725 | message RepeatedRules { 726 | // MinItems specifies that this field must have the specified number of 727 | // items at a minimum 728 | optional uint64 min_items = 1; 729 | 730 | // MaxItems specifies that this field must have the specified number of 731 | // items at a maximum 732 | optional uint64 max_items = 2; 733 | 734 | // Unique specifies that all elements in this field must be unique. This 735 | // contraint is only applicable to scalar and enum types (messages are not 736 | // supported). 737 | optional bool unique = 3; 738 | 739 | // Items specifies the contraints to be applied to each item in the field. 740 | // Repeated message fields will still execute validation against each item 741 | // unless skip is specified here. 742 | optional FieldRules items = 4; 743 | 744 | // IgnoreEmpty specifies that the validation rules of this field should be 745 | // evaluated only if the field is not empty 746 | optional bool ignore_empty = 5; 747 | } 748 | 749 | // MapRules describe the constraints applied to `map` values 750 | message MapRules { 751 | // MinPairs specifies that this field must have the specified number of 752 | // KVs at a minimum 753 | optional uint64 min_pairs = 1; 754 | 755 | // MaxPairs specifies that this field must have the specified number of 756 | // KVs at a maximum 757 | optional uint64 max_pairs = 2; 758 | 759 | // NoSparse specifies values in this field cannot be unset. This only 760 | // applies to map's with message value types. 761 | optional bool no_sparse = 3; 762 | 763 | // Keys specifies the constraints to be applied to each key in the field. 764 | optional FieldRules keys = 4; 765 | 766 | // Values specifies the constraints to be applied to the value of each key 767 | // in the field. Message values will still have their validations evaluated 768 | // unless skip is specified here. 769 | optional FieldRules values = 5; 770 | 771 | // IgnoreEmpty specifies that the validation rules of this field should be 772 | // evaluated only if the field is not empty 773 | optional bool ignore_empty = 6; 774 | } 775 | 776 | // AnyRules describe constraints applied exclusively to the 777 | // `google.protobuf.Any` well-known type 778 | message AnyRules { 779 | // Required specifies that this field must be set 780 | optional bool required = 1; 781 | 782 | // In specifies that this field's `type_url` must be equal to one of the 783 | // specified values. 784 | repeated string in = 2; 785 | 786 | // NotIn specifies that this field's `type_url` must not be equal to any of 787 | // the specified values. 788 | repeated string not_in = 3; 789 | } 790 | 791 | // DurationRules describe the constraints applied exclusively to the 792 | // `google.protobuf.Duration` well-known type 793 | message DurationRules { 794 | // Required specifies that this field must be set 795 | optional bool required = 1; 796 | 797 | // Const specifies that this field must be exactly the specified value 798 | optional google.protobuf.Duration const = 2; 799 | 800 | // Lt specifies that this field must be less than the specified value, 801 | // exclusive 802 | optional google.protobuf.Duration lt = 3; 803 | 804 | // Lt specifies that this field must be less than the specified value, 805 | // inclusive 806 | optional google.protobuf.Duration lte = 4; 807 | 808 | // Gt specifies that this field must be greater than the specified value, 809 | // exclusive 810 | optional google.protobuf.Duration gt = 5; 811 | 812 | // Gte specifies that this field must be greater than the specified value, 813 | // inclusive 814 | optional google.protobuf.Duration gte = 6; 815 | 816 | // In specifies that this field must be equal to one of the specified 817 | // values 818 | repeated google.protobuf.Duration in = 7; 819 | 820 | // NotIn specifies that this field cannot be equal to one of the specified 821 | // values 822 | repeated google.protobuf.Duration not_in = 8; 823 | } 824 | 825 | // TimestampRules describe the constraints applied exclusively to the 826 | // `google.protobuf.Timestamp` well-known type 827 | message TimestampRules { 828 | // Required specifies that this field must be set 829 | optional bool required = 1; 830 | 831 | // Const specifies that this field must be exactly the specified value 832 | optional google.protobuf.Timestamp const = 2; 833 | 834 | // Lt specifies that this field must be less than the specified value, 835 | // exclusive 836 | optional google.protobuf.Timestamp lt = 3; 837 | 838 | // Lte specifies that this field must be less than the specified value, 839 | // inclusive 840 | optional google.protobuf.Timestamp lte = 4; 841 | 842 | // Gt specifies that this field must be greater than the specified value, 843 | // exclusive 844 | optional google.protobuf.Timestamp gt = 5; 845 | 846 | // Gte specifies that this field must be greater than the specified value, 847 | // inclusive 848 | optional google.protobuf.Timestamp gte = 6; 849 | 850 | // LtNow specifies that this must be less than the current time. LtNow 851 | // can only be used with the Within rule. 852 | optional bool lt_now = 7; 853 | 854 | // GtNow specifies that this must be greater than the current time. GtNow 855 | // can only be used with the Within rule. 856 | optional bool gt_now = 8; 857 | 858 | // Within specifies that this field must be within this duration of the 859 | // current time. This constraint can be used alone or with the LtNow and 860 | // GtNow rules. 861 | optional google.protobuf.Duration within = 9; 862 | } 863 | -------------------------------------------------------------------------------- /thirdparty/github.com/mwitkow/go-proto-validators/validator.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Michal Witkowski. All Rights Reserved. 2 | // See LICENSE for licensing terms. 3 | 4 | // Protocol Buffers extensions for defining auto-generateable validators for messages. 5 | 6 | // TODO(mwitkow): Add example. 7 | 8 | 9 | syntax = "proto2"; 10 | package validator; 11 | 12 | import "google/protobuf/descriptor.proto"; 13 | 14 | option go_package = "github.com/mwitkow/go-proto-validators;validator"; 15 | 16 | // TODO(mwitkow): Email protobuf-global-extension-registry@google.com to get an extension ID. 17 | 18 | extend google.protobuf.FieldOptions { 19 | optional FieldValidator field = 65020; 20 | } 21 | 22 | extend google.protobuf.OneofOptions { 23 | optional OneofValidator oneof = 65021; 24 | } 25 | 26 | message FieldValidator { 27 | // Uses a Golang RE2-syntax regex to match the field contents. 28 | optional string regex = 1; 29 | // Field value of integer strictly greater than this value. 30 | optional int64 int_gt = 2; 31 | // Field value of integer strictly smaller than this value. 32 | optional int64 int_lt = 3; 33 | // Used for nested message types, requires that the message type exists. 34 | optional bool msg_exists = 4; 35 | // Human error specifies a user-customizable error that is visible to the user. 36 | optional string human_error = 5; 37 | // Field value of double strictly greater than this value. 38 | // Note that this value can only take on a valid floating point 39 | // value. Use together with float_epsilon if you need something more specific. 40 | optional double float_gt = 6; 41 | // Field value of double strictly smaller than this value. 42 | // Note that this value can only take on a valid floating point 43 | // value. Use together with float_epsilon if you need something more specific. 44 | optional double float_lt = 7; 45 | // Field value of double describing the epsilon within which 46 | // any comparison should be considered to be true. For example, 47 | // when using float_gt = 0.35, using a float_epsilon of 0.05 48 | // would mean that any value above 0.30 is acceptable. It can be 49 | // thought of as a {float_value_condition} +- {float_epsilon}. 50 | // If unset, no correction for floating point inaccuracies in 51 | // comparisons will be attempted. 52 | optional double float_epsilon = 8; 53 | // Floating-point value compared to which the field content should be greater or equal. 54 | optional double float_gte = 9; 55 | // Floating-point value compared to which the field content should be smaller or equal. 56 | optional double float_lte = 10; 57 | // Used for string fields, requires the string to be not empty (i.e different from ""). 58 | optional bool string_not_empty = 11; 59 | // Repeated field with at least this number of elements. 60 | optional int64 repeated_count_min = 12; 61 | // Repeated field with at most this number of elements. 62 | optional int64 repeated_count_max = 13; 63 | // Field value of length greater than this value. 64 | optional int64 length_gt = 14; 65 | // Field value of length smaller than this value. 66 | optional int64 length_lt = 15; 67 | // Field value of length strictly equal to this value. 68 | optional int64 length_eq = 16; 69 | // Requires that the value is in the enum. 70 | optional bool is_in_enum = 17; 71 | // Ensures that a string value is in UUID format. 72 | // uuid_ver specifies the valid UUID versions. Valid values are: 0-5. 73 | // If uuid_ver is 0 all UUID versions are accepted. 74 | optional int32 uuid_ver = 18; 75 | } 76 | 77 | message OneofValidator { 78 | // Require that one of the oneof fields is set. 79 | optional bool required = 1; 80 | } 81 | -------------------------------------------------------------------------------- /thirdparty/github.com/pseudomuto/protokit/fixtures/extend.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | import "google/protobuf/descriptor.proto"; 4 | 5 | package com.pseudomuto.protokit.v1; 6 | 7 | /** 8 | * Extension of protobuf file options. 9 | */ 10 | extend google.protobuf.FileOptions { 11 | optional bool extend_file = 20000; 12 | } 13 | 14 | /** 15 | * Extension of protobuf service options. 16 | */ 17 | extend google.protobuf.ServiceOptions { 18 | optional bool extend_service = 20000; 19 | } 20 | 21 | /** 22 | * Extension of protobuf method options. 23 | */ 24 | extend google.protobuf.MethodOptions { 25 | optional bool extend_method = 20000; 26 | } 27 | 28 | /** 29 | * Extension of protobuf enum options. 30 | */ 31 | extend google.protobuf.EnumOptions { 32 | optional bool extend_enum = 20000; 33 | } 34 | 35 | /** 36 | * Extension of protobuf enum value options. 37 | */ 38 | extend google.protobuf.EnumValueOptions { 39 | optional bool extend_enum_value = 20000; 40 | } 41 | 42 | /** 43 | * Extension of protobuf message options. 44 | */ 45 | extend google.protobuf.MessageOptions { 46 | optional bool extend_message = 20000; 47 | } 48 | 49 | /** 50 | * Extension of protobuf field options. 51 | */ 52 | extend google.protobuf.FieldOptions { 53 | optional bool extend_field = 20000; 54 | } 55 | -------------------------------------------------------------------------------- /tmp/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmc/protoc-gen-apidocs/b7fcc7fd042d1152fbd933b3d3acdc4be50b5f4e/tmp/.gitkeep --------------------------------------------------------------------------------