diff --git a/gen/generator.go b/gen/generator.go index c32595413..dbc15b050 100644 --- a/gen/generator.go +++ b/gen/generator.go @@ -71,6 +71,11 @@ func expandSpec(api *openapi.API, p string) (err error) { func NewGenerator(spec *ogen.Spec, opts Options) (*Generator, error) { opts.setDefaults() + // Set the comment line limit for pretty documentation. + ir.SetLineLimit(opts.Generator.CommentLineLimit) + // Set whether to use pretty documentation. + ir.SetPrettyDoc(opts.Generator.CommentPrettyDoc) + var external jsonschema.ExternalResolver if opts.Parser.AllowRemote { external = jsonschema.NewExternalResolver(opts.Parser.Remote) diff --git a/gen/generator_test.go b/gen/generator_test.go new file mode 100644 index 000000000..d39353e5a --- /dev/null +++ b/gen/generator_test.go @@ -0,0 +1,68 @@ +package gen + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ogen-go/ogen" + "github.com/ogen-go/ogen/gen/ir" +) + +func TestCommentLineLimitPropagation(t *testing.T) { + // Create a simple spec for testing + spec := &ogen.Spec{ + OpenAPI: "3.0.0", + Info: ogen.Info{ + Title: "Test API", + Version: "1.0.0", + }, + } + + // Test cases with different comment line limit values + tests := []struct { + name string + lineLimit int + expectLimit int + }{ + { + name: "default_value", + lineLimit: 0, + expectLimit: 100, // Should use default value + }, + { + name: "custom_value", + lineLimit: 50, + expectLimit: 50, + }, + { + name: "disable_wrapping", + lineLimit: -1, + expectLimit: -1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Save the original line limit to restore after the test + originalLimit := ir.GetLineLimit() + defer ir.SetLineLimit(originalLimit) + + // Create options with the test case's line limit + opts := Options{ + Generator: GenerateOptions{ + CommentLineLimit: tt.lineLimit, + }, + } + + // Create a new generator + _, err := NewGenerator(spec, opts) + require.NoError(t, err) + + // Verify the line limit was set correctly + actualLimit := ir.GetLineLimit() + require.Equal(t, tt.expectLimit, actualLimit, + "Line limit should be set to %d, but got %d", tt.expectLimit, actualLimit) + }) + } +} diff --git a/gen/ir/description.go b/gen/ir/description.go index dc2226cfb..eb98346c7 100644 --- a/gen/ir/description.go +++ b/gen/ir/description.go @@ -8,7 +8,48 @@ import ( "github.com/ogen-go/ogen/internal/naming" ) +// Global line limit, can be configured via SetLineLimit. +var lineLimit = 100 + +// Global flag to enable or disable pretty documentation. +var prettyDocEnabled = true + +// SetLineLimit sets the maximum width of a comment line before it is wrapped. +// Use a negative value to disable line wrapping altogether. +func SetLineLimit(limit int) { + if limit == 0 { + // Use default value for zero. + lineLimit = 100 + return + } + lineLimit = limit +} + +// GetLineLimit returns the current line limit value. +func GetLineLimit() int { + return lineLimit +} + +// SetPrettyDoc enables or disables pretty documentation. +func SetPrettyDoc(enabled bool) { + prettyDocEnabled = enabled +} + +// IsPrettyDocEnabled returns whether pretty documentation is enabled. +func IsPrettyDocEnabled() bool { + return prettyDocEnabled +} + func splitLine(s string, limit int) (r []string) { + // If limit is negative, don't split lines. + if limit < 0 { + s = strings.TrimSpace(s) + if s == "" { + return nil + } + return []string{s} + } + s = strings.TrimSpace(s) if s == "" { return nil @@ -39,11 +80,27 @@ func splitLine(s string, limit int) (r []string) { } } -const ( - lineLimit = 100 -) - func prettyDoc(s, deprecation string) (r []string) { + // If pretty documentation is disabled, return the comment as-is + if !prettyDocEnabled { + // Just split by newlines. + for _, line := range strings.Split(s, "\n") { + r = append(r, line) + } + + // Add deprecation notice if provided + if deprecation != "" { + if len(r) > 0 { + // Insert empty line between description and deprecated notice. + r = append(r, "") + } + r = append(r, deprecation) + } + + return r + } + + // Original pretty documentation behavior // TODO(tdakkota): basic common mark rendering? for _, line := range strings.Split(s, "\n") { r = append(r, splitLine(line, lineLimit)...) diff --git a/gen/ir/description_flag_test.go b/gen/ir/description_flag_test.go new file mode 100644 index 000000000..7bb48b392 --- /dev/null +++ b/gen/ir/description_flag_test.go @@ -0,0 +1,28 @@ +package ir + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPrettyDocEnabledFlag(t *testing.T) { + // Save original state to restore later + originalState := prettyDocEnabled + + // Test with pretty documentation enabled + SetPrettyDoc(true) + require.True(t, IsPrettyDocEnabled()) + doc := " this is a test. " + prettyResult := prettyDoc(doc, "") + require.Equal(t, "This is a test.", prettyResult[0]) + + // Test with pretty documentation disabled + SetPrettyDoc(false) + require.False(t, IsPrettyDocEnabled()) + verbatimResult := prettyDoc(doc, "") + require.Equal(t, " this is a test. ", verbatimResult[0]) + + // Restore original state + SetPrettyDoc(originalState) +} diff --git a/gen/ir/description_test.go b/gen/ir/description_test.go index 9cb525345..cef1915b8 100644 --- a/gen/ir/description_test.go +++ b/gen/ir/description_test.go @@ -11,6 +11,12 @@ import ( ) func Test_prettyDoc(t *testing.T) { + // Save the original value to restore after the test + originalLimit := lineLimit + defer func() { + lineLimit = originalLimit + }() + tests := []struct { input string notice string @@ -77,3 +83,67 @@ func Test_prettyDoc(t *testing.T) { }) } } + +func TestSetLineLimit(t *testing.T) { + // Save the original value to restore after the test + originalLimit := lineLimit + defer func() { + lineLimit = originalLimit + }() + + const longText = "This is a very long description that should be split into multiple lines depending on the configured line limit" + + tests := []struct { + name string + limit int + expected int // expected number of lines (approximate) + }{ + { + name: "default_limit", + limit: 0, // Should use default 100 + expected: 2, // The long test will still need to be split in 2 with default limit + }, + { + name: "short_limit", + limit: 20, + expected: 8, // Will split into multiple lines + }, + { + name: "negative_limit_disables_wrapping", + limit: -1, + expected: 1, // Should not wrap + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + SetLineLimit(tt.limit) + result := prettyDoc(longText, "") + require.Len(t, result, tt.expected) + }) + } +} + +func TestCommentLineLimit(t *testing.T) { + // Save the original value to restore after the test + originalLimit := lineLimit + defer func() { + lineLimit = originalLimit + }() + + // Reset to default to start + SetLineLimit(0) + require.Equal(t, 100, lineLimit, "Default line limit should be 100") + + // Test with a custom line limit + SetLineLimit(50) + require.Equal(t, 50, lineLimit, "Line limit should be updated to 50") + + // Test with a negative value (disabled wrapping) + SetLineLimit(-1) + require.Equal(t, -1, lineLimit, "Negative line limit should disable wrapping") + + // Test with zero (should set to default) + SetLineLimit(0) + require.Equal(t, 100, lineLimit, "Zero line limit should reset to default (100)") +} diff --git a/gen/options.go b/gen/options.go index ec7f2b9b6..29dad7410 100644 --- a/gen/options.go +++ b/gen/options.go @@ -161,6 +161,11 @@ type GenerateOptions struct { IgnoreNotImplemented []string `json:"ignore_not_implemented" yaml:"ignore_not_implemented"` // NotImplementedHook is hook for ErrNotImplemented errors. NotImplementedHook func(name string, err error) `json:"-" yaml:"-"` + // CommentPrettyDoc enables or disables pretty documentation for comments. + CommentPrettyDoc bool `json:"comment_pretty_doc" yaml:"comment_pretty_doc"` + // CommentLineLimit sets the maximum width of a comment line before it is + // wrapped. -1 disables line wrapping altogether. + CommentLineLimit int `json:"comment_line_limit" yaml:"comment_line_limit"` // ConvenientErrors control Convenient Errors feature. //