-
Notifications
You must be signed in to change notification settings - Fork 5
fix: shorten generic type definition names in JSON schema #57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,15 +2,25 @@ package spec | |||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||
| "reflect" | ||||||||||||||||||||||||||||
| "regexp" | ||||||||||||||||||||||||||||
| "strings" | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| "github.com/oaswrap/spec/internal/debuglog" | ||||||||||||||||||||||||||||
| "github.com/oaswrap/spec/openapi" | ||||||||||||||||||||||||||||
| "github.com/swaggest/jsonschema-go" | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| var genericInstRe = regexp.MustCompile(`^(\w+)\[(.+)\]$`) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func getJSONSchemaOpts(cfg *openapi.ReflectorConfig, logger *debuglog.Logger) []func(*jsonschema.ReflectContext) { | ||||||||||||||||||||||||||||
| var opts []func(*jsonschema.ReflectContext) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if cfg == nil { | ||||||||||||||||||||||||||||
| opts = append(opts, jsonschema.InterceptDefName(shortenGenericName)) | ||||||||||||||||||||||||||||
| return opts | ||||||||||||||||||||||||||||
|
Comment on lines
16
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1 | Confidence: High The PR introduces a breaking change in behavior when
Suggested change
|
||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if cfg.InlineRefs { | ||||||||||||||||||||||||||||
| opts = append(opts, jsonschema.InlineRefs) | ||||||||||||||||||||||||||||
| logger.Printf("set inline references to true") | ||||||||||||||||||||||||||||
|
|
@@ -27,6 +37,7 @@ func getJSONSchemaOpts(cfg *openapi.ReflectorConfig, logger *debuglog.Logger) [] | |||||||||||||||||||||||||||
| opts = append(opts, jsonschema.StripDefinitionNamePrefix(cfg.StripDefNamePrefix...)) | ||||||||||||||||||||||||||||
| logger.LogAction("set strip definition name prefix", fmt.Sprintf("%v", cfg.StripDefNamePrefix)) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| opts = append(opts, jsonschema.InterceptDefName(shortenGenericName)) | ||||||||||||||||||||||||||||
| if cfg.InterceptDefNameFunc != nil { | ||||||||||||||||||||||||||||
| opts = append(opts, jsonschema.InterceptDefName(cfg.InterceptDefNameFunc)) | ||||||||||||||||||||||||||||
| logger.Printf("set custom intercept definition name function") | ||||||||||||||||||||||||||||
|
Comment on lines
39
to
43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1 | Confidence: High The PR's logic creates a conflict when a user has configured a custom Code Suggestion: // Define a composite interceptor that applies shortening, then custom logic if provided.
compositeInterceptor := func(t reflect.Type, defaultDefName string) string {
shortName := shortenGenericName(t, defaultDefName)
if cfg.InterceptDefNameFunc != nil {
return cfg.InterceptDefNameFunc(t, shortName) // Custom func receives the shortened name.
}
return shortName
}
opts = append(opts, jsonschema.InterceptDefName(compositeInterceptor))
if cfg.InterceptDefNameFunc != nil {
logger.Printf("set custom intercept definition name function")
} |
||||||||||||||||||||||||||||
|
|
@@ -63,3 +74,36 @@ func getJSONSchemaOpts(cfg *openapi.ReflectorConfig, logger *debuglog.Logger) [] | |||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| return opts | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // shortenGenericName converts "Page[some/pkg.Item]" to "PageItem". | ||||||||||||||||||||||||||||
| func shortenGenericName(t reflect.Type, defaultDefName string) string { | ||||||||||||||||||||||||||||
| m := genericInstRe.FindStringSubmatch(t.Name()) | ||||||||||||||||||||||||||||
| if m == nil { | ||||||||||||||||||||||||||||
| return defaultDefName | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| // Use the container name from defaultDefName, which already has the package | ||||||||||||||||||||||||||||
| // prefix applied and StripDefinitionNamePrefix already run — so the result | ||||||||||||||||||||||||||||
| // is consistent with how non-generic struct names are generated. | ||||||||||||||||||||||||||||
| containerName := m[1] | ||||||||||||||||||||||||||||
| if before, _, found := strings.Cut(defaultDefName, "["); found { | ||||||||||||||||||||||||||||
| containerName = before | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| args := strings.Split(m[2], ", ") | ||||||||||||||||||||||||||||
| result := containerName | ||||||||||||||||||||||||||||
| var sb strings.Builder | ||||||||||||||||||||||||||||
| for _, arg := range args { | ||||||||||||||||||||||||||||
| arg = strings.TrimPrefix(arg, "*") | ||||||||||||||||||||||||||||
| var suffixSb strings.Builder | ||||||||||||||||||||||||||||
| for strings.HasPrefix(arg, "[]") { | ||||||||||||||||||||||||||||
| suffixSb.WriteString("List") | ||||||||||||||||||||||||||||
| arg = arg[2:] | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| arg = strings.TrimPrefix(arg, "*") | ||||||||||||||||||||||||||||
| if i := strings.LastIndex(arg, "."); i >= 0 { | ||||||||||||||||||||||||||||
| arg = arg[i+1:] | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| sb.WriteString(arg + suffixSb.String()) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| result += sb.String() | ||||||||||||||||||||||||||||
| return result | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2 | Confidence: High
The
shortenGenericNameinterceptor is added in two separate code paths (whencfgis nil and when it's not). This duplication is unnecessary and increases the risk of the two code paths diverging in the future. The logic should be consolidated. The simplest fix is to remove the early return forcfg == nil(as suggested in Finding 1 to fix the breaking change) and let the main flow handle the addition, ensuring consistency.