Skip to content
This repository was archived by the owner on Jan 18, 2026. It is now read-only.

Commit ca141fc

Browse files
authored
feat: add custom initialisms support to gen package and avrogen (#303)
1 parent 015449d commit ca141fc

4 files changed

Lines changed: 113 additions & 12 deletions

File tree

cmd/avrogen/main.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ import (
1515
)
1616

1717
type config struct {
18-
Pkg string
19-
Out string
20-
Tags string
21-
FullName bool
22-
Encoders bool
18+
Pkg string
19+
Out string
20+
Tags string
21+
FullName bool
22+
Encoders bool
23+
Initialisms string
2324
}
2425

2526
func main() {
@@ -35,6 +36,7 @@ func realMain(args []string, out, dumpout io.Writer) int {
3536
flgs.StringVar(&cfg.Tags, "tags", "", "The additional field tags <tag-name>:{snake|camel|upper-camel|kebab}>[,...]")
3637
flgs.BoolVar(&cfg.FullName, "fullname", false, "Use the full name of the Record schema to create the struct name.")
3738
flgs.BoolVar(&cfg.Encoders, "encoders", false, "Generate encoders for the structs.")
39+
flgs.StringVar(&cfg.Initialisms, "initialisms", "", "Custom initialisms <VAL>[,...] for struct and field names.")
3840
flgs.Usage = func() {
3941
_, _ = fmt.Fprintln(out, "Usage: avrogen [options] schemas")
4042
_, _ = fmt.Fprintln(out, "Options:")
@@ -48,15 +50,23 @@ func realMain(args []string, out, dumpout io.Writer) int {
4850
_, _ = fmt.Fprintln(out, "Error: "+err.Error())
4951
return 1
5052
}
53+
5154
tags, err := parseTags(cfg.Tags)
5255
if err != nil {
5356
_, _ = fmt.Fprintln(out, "Error: "+err.Error())
5457
return 1
5558
}
5659

60+
initialisms, err := parseInitialisms(cfg.Initialisms)
61+
if err != nil {
62+
_, _ = fmt.Fprintln(out, "Error: "+err.Error())
63+
return 1
64+
}
65+
5766
opts := []gen.OptsFunc{
5867
gen.WithFullName(cfg.FullName),
5968
gen.WithEncoders(cfg.Encoders),
69+
gen.WithInitialisms(initialisms),
6070
}
6171
g := gen.NewGenerator(cfg.Pkg, tags, opts...)
6272
for _, file := range flgs.Args() {
@@ -143,3 +153,19 @@ func parseTags(raw string) (map[string]gen.TagStyle, error) {
143153
}
144154
return result, nil
145155
}
156+
157+
func parseInitialisms(raw string) ([]string, error) {
158+
if raw == "" {
159+
return []string{}, nil
160+
}
161+
162+
result := []string{}
163+
for _, initialism := range strings.Split(raw, ",") {
164+
if initialism != strings.ToUpper(initialism) {
165+
return nil, fmt.Errorf("initialism %q must be fully in upper case", initialism)
166+
}
167+
result = append(result, initialism)
168+
}
169+
170+
return result, nil
171+
}

cmd/avrogen/main_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,36 @@ func TestParseTags(t *testing.T) {
180180
})
181181
}
182182
}
183+
184+
func TestParseInitialisms(t *testing.T) {
185+
tests := []struct {
186+
name string
187+
initialisms string
188+
errFunc assert.ErrorAssertionFunc
189+
}{
190+
{
191+
name: "single initialism",
192+
initialisms: "ABC",
193+
errFunc: assert.NoError,
194+
},
195+
{
196+
name: "multiple initialisms",
197+
initialisms: "ABC,DEF",
198+
errFunc: assert.NoError,
199+
},
200+
{
201+
name: "wrong initialism",
202+
initialisms: "ABC,def,GHI",
203+
errFunc: assert.Error,
204+
},
205+
}
206+
207+
for _, test := range tests {
208+
test := test
209+
t.Run(test.name, func(t *testing.T) {
210+
_, err := parseInitialisms(test.initialisms)
211+
212+
test.errFunc(t, err)
213+
})
214+
}
215+
}

gen/gen.go

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Config struct {
2020
Tags map[string]TagStyle
2121
FullName bool
2222
Encoders bool
23+
Initialisms []string
2324
}
2425

2526
// TagStyle defines the styling for a tag.
@@ -120,6 +121,7 @@ func StructFromSchema(schema avro.Schema, w io.Writer, cfg Config) error {
120121
opts := []OptsFunc{
121122
WithFullName(cfg.FullName),
122123
WithEncoders(cfg.Encoders),
124+
WithInitialisms(cfg.Initialisms),
123125
}
124126
g := NewGenerator(strcase.ToSnake(cfg.PackageName), cfg.Tags, opts...)
125127
g.Parse(rec)
@@ -160,16 +162,27 @@ func WithEncoders(b bool) OptsFunc {
160162
}
161163
}
162164

165+
// WithInitialisms configures the generator to use additional custom initialisms
166+
// when styling struct and field names.
167+
func WithInitialisms(ss []string) OptsFunc {
168+
return func(g *Generator) {
169+
g.initialisms = ss
170+
}
171+
}
172+
163173
// Generator generates Go structs from schemas.
164174
type Generator struct {
165-
pkg string
166-
tags map[string]TagStyle
167-
fullName bool
168-
encoders bool
175+
pkg string
176+
tags map[string]TagStyle
177+
fullName bool
178+
encoders bool
179+
initialisms []string
169180

170181
imports []string
171182
thirdPartyImports []string
172183
typedefs []typedef
184+
185+
nameCaser *strcase.Caser
173186
}
174187

175188
// NewGenerator returns a generator.
@@ -183,6 +196,17 @@ func NewGenerator(pkg string, tags map[string]TagStyle, opts ...OptsFunc) *Gener
183196
opt(g)
184197
}
185198

199+
initialisms := map[string]bool{}
200+
for _, v := range g.initialisms {
201+
initialisms[v] = true
202+
}
203+
204+
g.nameCaser = strcase.NewCaser(
205+
true, // use standard Golint's initialisms
206+
initialisms,
207+
nil, // use default word split function
208+
)
209+
186210
return g
187211
}
188212

@@ -231,17 +255,17 @@ func (g *Generator) generate(schema avro.Schema) string {
231255

232256
func (g *Generator) resolveTypeName(s avro.NamedSchema) string {
233257
if g.fullName {
234-
return strcase.ToGoPascal(s.FullName())
258+
return g.nameCaser.ToPascal(s.FullName())
235259
}
236-
return strcase.ToGoPascal(s.Name())
260+
return g.nameCaser.ToPascal(s.Name())
237261
}
238262

239263
func (g *Generator) resolveRecordSchema(schema *avro.RecordSchema) string {
240264
fields := make([]field, len(schema.Fields()))
241265
for i, f := range schema.Fields() {
242266
typ := g.generate(f.Type())
243267
tag := f.Name()
244-
fields[i] = g.newField(strcase.ToGoPascal(f.Name()), typ, tag)
268+
fields[i] = g.newField(g.nameCaser.ToPascal(f.Name()), typ, tag)
245269
}
246270

247271
typeName := g.resolveTypeName(schema)

gen/gen_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,24 @@ func TestStruct_HandlesGoInitialisms(t *testing.T) {
7575
assert.Contains(t, lines, "type HTTPRecord struct {")
7676
}
7777

78+
func TestStruct_HandlesAdditionalInitialisms(t *testing.T) {
79+
schema := `{
80+
"type": "record",
81+
"name": "CidOverHttpRecord",
82+
"fields": [
83+
{ "name": "someString", "type": "string" }
84+
]
85+
}`
86+
gc := gen.Config{
87+
PackageName: "Something",
88+
Initialisms: []string{"CID"},
89+
}
90+
91+
_, lines := generate(t, schema, gc)
92+
93+
assert.Contains(t, lines, "type CIDOverHTTPRecord struct {")
94+
}
95+
7896
func TestStruct_ConfigurableFieldTags(t *testing.T) {
7997
schema := `{
8098
"type": "record",

0 commit comments

Comments
 (0)