aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXe Iaso <me@xeiaso.net>2025-02-19 21:37:28 -0500
committerXe Iaso <me@xeiaso.net>2025-02-19 21:37:28 -0500
commit39c822e6ebd930b4bdd29d985be56cd7759017ea (patch)
tree9430191fc28a647ff32351e2b85dd6db9f5404d1
parent3fd1aa2302ff42ca85021ee190b033d5aa2cc9e2 (diff)
downloadxesite-39c822e6ebd930b4bdd29d985be56cd7759017ea.tar.xz
xesite-39c822e6ebd930b4bdd29d985be56cd7759017ea.zip
remove this broken thing
Signed-off-by: Xe Iaso <me@xeiaso.net>
-rw-r--r--cmd/twirp-openapi-gen/LICENSE201
-rw-r--r--cmd/twirp-openapi-gen/README.md3
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/aliases.go82
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/generator.go187
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/generator_test.go317
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/handlers.go579
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/testdata/doc.json413
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/testdata/gen/go/payment/v1alpha1/payment.pb.go263
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/testdata/gen/go/pet/v1/pet.pb.go896
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/testdata/gen/go/pet/v1/pet.twirp.go1705
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/testdata/paymentapis/payment/v1alpha1/payment.proto24
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/testdata/pet-api-doc.json321
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/testdata/pet-api-doc.yaml297
-rw-r--r--cmd/twirp-openapi-gen/internal/generator/testdata/petapis/pet/v1/pet.proto115
-rw-r--r--cmd/twirp-openapi-gen/main.go90
-rw-r--r--go.mod7
-rw-r--r--go.sum18
-rw-r--r--pb/generate.go1
18 files changed, 0 insertions, 5519 deletions
diff --git a/cmd/twirp-openapi-gen/LICENSE b/cmd/twirp-openapi-gen/LICENSE
deleted file mode 100644
index 261eeb9..0000000
--- a/cmd/twirp-openapi-gen/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/cmd/twirp-openapi-gen/README.md b/cmd/twirp-openapi-gen/README.md
deleted file mode 100644
index d3bf9a8..0000000
--- a/cmd/twirp-openapi-gen/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# twirp-openapi-gen
-
-This was imported from [github.com/blockthrough/twirp-openapi-gen](https://github.com/blockthrough/twirp-openapi-gen) and a few non-upstreamable changes were made. These changes are made in order to meet my needs in particular. If you want to use this tool, I recommend you to use the original repository.
diff --git a/cmd/twirp-openapi-gen/internal/generator/aliases.go b/cmd/twirp-openapi-gen/internal/generator/aliases.go
deleted file mode 100644
index 660d345..0000000
--- a/cmd/twirp-openapi-gen/internal/generator/aliases.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package generator
-
-var typeAliases = map[string]struct {
- Type, Format string
-}{
- // proto numeric types
- "int32": {Type: "integer", Format: "int32"},
- "uint32": {Type: "integer", Format: "uint32"},
- "sint32": {Type: "integer", Format: "int32"},
- "fixed32": {Type: "integer", Format: "int32"},
- "sfixed32": {Type: "integer", Format: "int32"},
-
- // proto numeric types, 64bit
- "int64": {Type: "string", Format: "int64"},
- "uint64": {Type: "string", Format: "uint64"},
- "sint64": {Type: "string", Format: "int64"},
- "fixed64": {Type: "string", Format: "int64"},
- "sfixed64": {Type: "string", Format: "int64"},
-
- "double": {Type: "number", Format: "double"},
- "float": {Type: "number", Format: "float"},
-
- // effectively copies google.protobuf.BytesValue
- "bytes": {
- Type: "string",
- Format: "byte",
- },
-
- // It is what it is
- "bool": {
- Type: "boolean",
- Format: "boolean",
- },
-
- "google.protobuf.Timestamp": {
- Type: "string",
- Format: "date-time",
- },
- "google.protobuf.Duration": {
- Type: "string",
- },
- "google.protobuf.StringValue": {
- Type: "string",
- },
- "google.protobuf.BytesValue": {
- Type: "string",
- Format: "byte",
- },
- "google.protobuf.Int32Value": {
- Type: "integer",
- Format: "int32",
- },
- "google.protobuf.UInt32Value": {
- Type: "integer",
- Format: "uint32",
- },
- "google.protobuf.Int64Value": {
- Type: "string",
- Format: "int64",
- },
- "google.protobuf.UInt64Value": {
- Type: "string",
- Format: "uint64",
- },
- "google.protobuf.FloatValue": {
- Type: "number",
- Format: "float",
- },
- "google.protobuf.DoubleValue": {
- Type: "number",
- Format: "double",
- },
- "google.protobuf.BoolValue": {
- Type: "boolean",
- Format: "boolean",
- },
-
- "google.type.DateTime": {
- Type: "string",
- Format: "date-time",
- },
-}
diff --git a/cmd/twirp-openapi-gen/internal/generator/generator.go b/cmd/twirp-openapi-gen/internal/generator/generator.go
deleted file mode 100644
index 2a08055..0000000
--- a/cmd/twirp-openapi-gen/internal/generator/generator.go
+++ /dev/null
@@ -1,187 +0,0 @@
-package generator
-
-import (
- "encoding/json"
- "fmt"
- "log/slog"
- "os"
- "path/filepath"
-
- "github.com/emicklei/proto"
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/invopop/yaml"
-)
-
-type generatorConfig struct {
- protoPaths []string
- servers []string
- title string
- docVersion string
- pathPrefix string
- format string
-}
-
-type Option func(config *generatorConfig) error
-
-func ProtoPaths(paths []string) Option {
- return func(config *generatorConfig) error {
- config.protoPaths = paths
- return nil
- }
-}
-
-func Servers(servers []string) Option {
- return func(config *generatorConfig) error {
- config.servers = servers
- return nil
- }
-}
-
-func Title(title string) Option {
- return func(config *generatorConfig) error {
- config.title = title
- return nil
- }
-}
-
-func DocVersion(version string) Option {
- return func(config *generatorConfig) error {
- config.docVersion = version
- return nil
- }
-}
-
-func PathPrefix(pathPrefix string) Option {
- return func(config *generatorConfig) error {
- config.pathPrefix = pathPrefix
- return nil
- }
-}
-
-func Format(format string) Option {
- return func(config *generatorConfig) error {
- config.format = format
- return nil
- }
-}
-
-type generator struct {
- openAPIV3 *openapi3.T
-
- conf *generatorConfig
- inputFiles []string
- packageName string
-
- importedFiles map[string]struct{}
-}
-
-func NewGenerator(inputFiles []string, options ...Option) (*generator, error) {
- conf := generatorConfig{}
- for _, opt := range options {
- if err := opt(&conf); err != nil {
- return nil, err
- }
- }
-
- if len(inputFiles) < 1 {
- return nil, fmt.Errorf("missing input files")
- }
-
- openAPIV3 := openapi3.T{
- OpenAPI: "3.0.0",
- Info: &openapi3.Info{
- Title: conf.title,
- Version: conf.docVersion,
- },
- Paths: openapi3.Paths{},
- Components: &openapi3.Components{
- Schemas: map[string]*openapi3.SchemaRef{},
- },
- }
-
- for _, server := range conf.servers {
- openAPIV3.Servers = append(openAPIV3.Servers, &openapi3.Server{URL: server})
- }
-
- slog.Debug("generating doc", "format", conf.format, "inputFiles", inputFiles)
-
- return &generator{
- inputFiles: inputFiles,
- openAPIV3: &openAPIV3,
- conf: &conf,
- importedFiles: map[string]struct{}{},
- }, nil
-}
-
-func (gen *generator) Generate(filename string) error {
- if _, err := gen.Parse(); err != nil {
- return err
- }
-
- if err := gen.Save(filename); err != nil {
- return err
- }
-
- return nil
-}
-
-func (gen *generator) Parse() (*openapi3.T, error) {
- for _, filename := range gen.inputFiles {
- protoFile, err := readProtoFile(filename, gen.conf.protoPaths)
- if err != nil {
- return nil, fmt.Errorf("readProtoFile: %w", err)
- }
- proto.Walk(protoFile, gen.Handlers()...)
- }
-
- slog.Debug("generated", "paths", len(gen.openAPIV3.Paths), "components", len(gen.openAPIV3.Components.Schemas))
- return gen.openAPIV3, nil
-}
-
-func (gen *generator) Save(filename string) error {
- var by []byte
- var err error
- switch gen.conf.format {
- case "json":
- by, err = gen.JSON()
- case "yaml", "yml":
- by, err = gen.YAML()
- default:
- return fmt.Errorf("missing format")
- }
- if err != nil {
- return err
- }
-
- return os.WriteFile(filename, by, os.ModePerm^0111)
-}
-
-func (gen *generator) JSON() ([]byte, error) {
- return json.MarshalIndent(gen.openAPIV3, "", " ")
-}
-
-func (gen *generator) YAML() ([]byte, error) {
- return yaml.Marshal(gen.openAPIV3)
-}
-
-func readProtoFile(filename string, protoPaths []string) (*proto.Proto, error) {
- var file *os.File
- var err error
- for _, path := range append(protoPaths, "") {
- file, err = os.Open(filepath.Join(path, filename))
- if err != nil {
- if os.IsNotExist(err) {
- continue
- }
- return nil, fmt.Errorf("Open: %w", err)
- }
- break
- }
- if file == nil {
- return nil, fmt.Errorf("could not read file %q", filename)
- }
- defer file.Close()
-
- parser := proto.NewParser(file)
- return parser.Parse()
-}
diff --git a/cmd/twirp-openapi-gen/internal/generator/generator_test.go b/cmd/twirp-openapi-gen/internal/generator/generator_test.go
deleted file mode 100644
index 78af950..0000000
--- a/cmd/twirp-openapi-gen/internal/generator/generator_test.go
+++ /dev/null
@@ -1,317 +0,0 @@
-package generator
-
-import (
- "flag"
- "log/slog"
- "os"
- "strings"
- "testing"
-)
-
-type ProtoRPC struct {
- name string
- input string
- output string
- desc string
-}
-
-type ProtoMessage struct {
- name string
- fields []ProtoField
-}
-
-type ProtoField struct {
- name string
- fieldType string
- format string
- desc string
- enums []string
- ref string
- itemsRef string
- itemsType string
-}
-
-var (
- verbose = flag.Bool("slog.verbose", false, "print debug logs to the console")
-)
-
-func init() {
- if *verbose {
- h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
- AddSource: true,
- Level: slog.LevelDebug,
- })
- slog.SetDefault(slog.New(h))
- } else {
- slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
- AddSource: true,
- })))
- }
-}
-
-func TestGenerator(t *testing.T) {
- flag.Parse()
-
- opts := []Option{
- ProtoPaths([]string{"./testdata/paymentapis", "./testdata/petapis"}),
- Servers([]string{"https://example.com"}),
- Title("Test"),
- DocVersion("0.1"),
- Format("json"),
- }
- gen, err := NewGenerator([]string{"./testdata/petapis/pet/v1/pet.proto"}, opts...)
- if err != nil {
- t.Fatal(err)
- }
- openAPI, err := gen.Parse()
- if err != nil {
- t.Fatal(err)
- }
-
- if err := gen.Save("./testdata/doc.json"); err != nil {
- t.Fatal(err)
- }
-
- pkgName := "pet.v1"
- serviceName := "PetStoreService"
- rpcs := []ProtoRPC{
- {
- name: "GetPet",
- input: "GetPetRequest",
- output: "GetPetResponse",
- },
- }
- messages := []ProtoMessage{
- {
- name: "GetPetRequest",
- fields: []ProtoField{
- {
- name: "pet_id",
- fieldType: "string",
- },
- },
- },
- {
- name: "Pet",
- fields: []ProtoField{
- {
- name: "pet_type",
- fieldType: "object",
- ref: "#/components/schemas/pet.v1.PetType",
- enums: []string{
- "PET_TYPE_UNSPECIFIED",
- "PET_TYPE_CAT",
- "PET_TYPE_DOG",
- "PET_TYPE_SNAKE",
- "PET_TYPE_HAMSTER",
- },
- },
- {
- name: "pet_types",
- fieldType: "array",
- itemsRef: "#/components/schemas/pet.v1.PetType",
- },
- {
- name: "tags",
- fieldType: "array",
- itemsType: "string",
- },
- {
- name: "pet_id",
- fieldType: "string",
- desc: "pet_id is an auto-generated id for the pet\\nthe id uniquely identifies a pet in the system",
- },
- {
- name: "name",
- fieldType: "string",
- },
- {
- name: "created_at",
- fieldType: "string",
- format: "date-time",
- },
- {
- name: "vet",
- fieldType: "object",
- ref: "#/components/schemas/pet.v1.Vet",
- },
- {
- name: "vets",
- fieldType: "array",
- itemsRef: "#/components/schemas/pet.v1.Vet",
- itemsType: "object",
- },
- },
- },
- }
-
- t.Run("RPC", func(t *testing.T) {
- for _, rpc := range rpcs {
- pathName := "/" + pkgName + "." + serviceName + "/" + rpc.name
- path, ok := openAPI.Paths[pathName]
- if !ok {
- t.Errorf("%s: missing rpc %q", pathName, rpc.name)
- }
-
- if path.Description != rpc.desc {
- t.Errorf("%s: expected desc %q but got %q", pathName, rpc.desc, path.Description)
- }
-
- post := path.Post
- if post == nil {
- t.Errorf("%s: missing post", pathName)
- continue
- }
-
- if post.Summary != rpc.name {
- t.Errorf("%s: expected summary %q but got %q", pathName, rpc.name, post.Summary)
- }
-
- requestBodyRef := post.RequestBody
- if requestBodyRef == nil {
- t.Errorf("%s: missing request body", pathName)
- continue
- }
-
- // request
- {
- requestBody := requestBodyRef.Value
- if requestBody == nil {
- t.Errorf("%s: missing request body", pathName)
- continue
- }
-
- mediaType, ok := requestBody.Content["application/json"]
- if !ok {
- t.Errorf("%s: missing content type", pathName)
- continue
- }
-
- if mediaType.Schema == nil {
- t.Errorf("%s: missing media type schema", pathName)
- continue
- }
-
- expectedRef := "#/components/schemas/" + pkgName + "." + rpc.input
- if mediaType.Schema.Ref != expectedRef {
- t.Errorf("%s: expected ref %q but got %q", pathName, expectedRef, mediaType.Schema.Ref)
- }
- }
-
- // response
- {
- respRef := post.Responses["200"]
- if respRef == nil {
- t.Errorf("%s: missing resp", pathName)
- continue
- }
-
- resp := respRef.Value
- if resp == nil {
- t.Errorf("%s: missing resp", pathName)
- continue
- }
-
- mediaType, ok := resp.Content["application/json"]
- if !ok {
- t.Errorf("%s: missing content type", pathName)
- continue
- }
-
- if mediaType.Schema == nil {
- t.Errorf("%s: missing media type schema", pathName)
- continue
- }
-
- expectedRef := "#/components/schemas/" + pkgName + "." + rpc.output
- if mediaType.Schema.Ref != expectedRef {
- t.Errorf("%s: expected ref %q but got %q", pathName, expectedRef, mediaType.Schema.Ref)
- }
- }
- }
- })
-
- t.Run("Messages", func(*testing.T) {
- for _, message := range messages {
- schemaName := "" + pkgName + "." + message.name
- schema, ok := openAPI.Components.Schemas[schemaName]
- if !ok {
- t.Errorf("%s: missing message %q", schemaName, message.name)
- }
- if schema.Value == nil {
- t.Errorf("%s: missing component", schemaName)
- continue
- }
- properties := schema.Value.Properties
- for _, messageField := range message.fields {
- propertyRef, ok := properties[messageField.name]
- if !ok {
- t.Errorf("%s: missing property %q", schemaName, messageField.name)
- }
-
- if propertyRef == nil || propertyRef.Value == nil {
- t.Errorf("%s: missing property ref", schemaName)
- continue
- }
-
- property := propertyRef.Value
- if property.Type != messageField.fieldType {
- t.Errorf("%s: %q expected property type %q but got %q", schemaName, message.name, messageField.fieldType, property.Type)
- continue
- }
-
- if messageField.format != "" {
- if messageField.format != "" && property.Format != messageField.format {
- t.Errorf("%s: expected property format %q but got %q", schemaName, messageField.format, property.Format)
- continue
- }
- }
-
- if propertyRef.Ref != messageField.ref {
- t.Errorf("%s: %q expected reference %q but got %q", schemaName, messageField.name, messageField.ref, propertyRef.Ref)
- }
-
- // check the reference schema
- if messageField.ref != "" {
- refParts := strings.Split(messageField.ref, "/")
- // the reference schema has the format of #/components/schemas/<type> so we need to get the last part
- schemaRef, ok := openAPI.Components.Schemas[refParts[len(refParts)-1]]
- if !ok {
- t.Errorf("%s: %q expected reference schema %q but got nil", schemaName, messageField.name, messageField.ref)
- } else {
- // check if the schema reference has the expected enum values
- if len(messageField.enums) > 0 {
- if schemaRef.Value.Enum == nil {
- t.Errorf("%s: %q expected reference schema enums %q but got nil", schemaName, messageField.name, messageField.ref)
- } else {
- enums := map[string]struct{}{}
- for _, e := range schemaRef.Value.Enum {
- enums[e.(string)] = struct{}{}
- }
- for _, e := range messageField.enums {
- if _, ok := enums[e]; !ok {
- t.Errorf("%s: %q expected reference schema enum %q to have %q but got nil", schemaName, messageField.name, messageField.ref, e)
- }
- }
- }
- }
- }
- }
-
- if property.Type == "array" {
- if property.Items == nil || property.Items.Value == nil {
- t.Errorf("%s: missing property enum array items", schemaName)
- }
- // only check the array items type if it's not a reference
- if messageField.itemsRef == "" && (property.Items.Value.Type != messageField.itemsType) {
- t.Errorf("%s: expected %s items type %q but got %q", schemaName, messageField.name, messageField.itemsType, property.Items.Value.Type)
- }
- // check the array items reference schema
- if property.Items.Ref != messageField.itemsRef {
- t.Errorf("%s: expected %s items ref %q but got %q", schemaName, messageField.name, messageField.itemsRef, property.Items.Ref)
- }
- }
- }
- }
- })
-}
diff --git a/cmd/twirp-openapi-gen/internal/generator/handlers.go b/cmd/twirp-openapi-gen/internal/generator/handlers.go
deleted file mode 100644
index 219000f..0000000
--- a/cmd/twirp-openapi-gen/internal/generator/handlers.go
+++ /dev/null
@@ -1,579 +0,0 @@
-package generator
-
-import (
- "encoding/json"
- "fmt"
- "log"
- "log/slog"
- "path/filepath"
- "strings"
- "unicode"
-
- "github.com/emicklei/proto"
- "github.com/getkin/kin-openapi/openapi3"
-)
-
-const (
- googleAnyType = "google.protobuf.Any"
- googleListValueType = "google.protobuf.ListValue"
- googleStructType = "google.protobuf.Struct"
- googleValueType = "google.protobuf.Value"
- googleEmptyType = "google.protobuf.Empty"
-
- googleMoneyType = "google.type.Money"
-)
-
-var (
- successDescription = "Success"
-)
-
-func (gen *generator) Handlers() []proto.Handler {
- return []proto.Handler{
- proto.WithPackage(gen.Package),
- proto.WithImport(gen.Import),
- proto.WithRPC(gen.RPC),
- proto.WithEnum(gen.Enum),
- proto.WithMessage(gen.Message),
- }
-}
-
-func (gen *generator) Package(pkg *proto.Package) {
- slog.Debug("Package handler", "package", pkg.Name)
- gen.packageName = pkg.Name
-}
-
-func (gen *generator) Import(i *proto.Import) {
- slog.Debug("Import handler", "package", gen.packageName, "filename", i.Filename)
-
- if _, ok := gen.importedFiles[i.Filename]; ok {
- return
- }
- gen.importedFiles[i.Filename] = struct{}{}
-
- // Instead of loading and generating the OpenAPI docs for the google proto definitions,
- // its known types are mapped to OpenAPI types; see aliases.go.
- if strings.Contains(i.Filename, "google/") {
- return
- }
-
- protoFile, err := readProtoFile(i.Filename, gen.conf.protoPaths)
- if err != nil {
- slog.Error("could not import file", "filename", i.Filename, "error", err)
- return
- }
-
- oldPackageName := gen.packageName
-
- // Override the package name for the next round of Walk calls to preserve the types full import path
- withPackage := func(pkg *proto.Package) {
- gen.packageName = pkg.Name
- }
-
- // additional files walked for messages and imports only
- proto.Walk(protoFile,
- proto.WithPackage(withPackage),
- proto.WithImport(gen.Import),
- proto.WithRPC(gen.RPC),
- proto.WithEnum(gen.Enum),
- proto.WithMessage(gen.Message),
- )
-
- gen.packageName = oldPackageName
-}
-
-func (gen *generator) RPC(rpc *proto.RPC) {
<