Skip to content
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

*: allow users to ask for minimal names #324

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ go 1.22.0

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/goccy/go-yaml v1.14.3
github.com/mitchellh/go-wordwrap v1.0.1
github.com/pkg/errors v0.9.1
Expand All @@ -16,11 +15,7 @@ require (

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
63 changes: 0 additions & 63 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,10 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/goccy/go-yaml v1.12.0 h1:/1WHjnMsI1dlIBQutrvSMGZRQufVO3asrHfTwfACoPM=
github.com/goccy/go-yaml v1.12.0/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
github.com/goccy/go-yaml v1.13.0 h1:0Wtp0FZLd7Sm8gERmR9S6Iczzb3vItJj7NaHmFg8pTs=
github.com/goccy/go-yaml v1.13.0/go.mod h1:IjYwxUiJDoqpx2RmbdjMUceGHZwYLon3sfOGl5Hi9lc=
github.com/goccy/go-yaml v1.13.1 h1:xZqDO9euwefeRx5am/ca9DPSCbV3fMNPkrl+Tivmz8A=
github.com/goccy/go-yaml v1.13.1/go.mod h1:IjYwxUiJDoqpx2RmbdjMUceGHZwYLon3sfOGl5Hi9lc=
github.com/goccy/go-yaml v1.13.2 h1:jApcuETDAB6R10spnUfQDTVu090oUwGo+p3GakYTJKw=
github.com/goccy/go-yaml v1.13.2/go.mod h1:IjYwxUiJDoqpx2RmbdjMUceGHZwYLon3sfOGl5Hi9lc=
github.com/goccy/go-yaml v1.13.3 h1:IXRULR8mAa0MXQobzzp0VOfMUJ8EnaQ4x3jhf7S0/nI=
github.com/goccy/go-yaml v1.13.3/go.mod h1:IjYwxUiJDoqpx2RmbdjMUceGHZwYLon3sfOGl5Hi9lc=
github.com/goccy/go-yaml v1.13.4 h1:XOnLX9GqT+kH/gB7YzCMUiDBFU9B7pm3HZz6kyeDPkk=
github.com/goccy/go-yaml v1.13.4/go.mod h1:IjYwxUiJDoqpx2RmbdjMUceGHZwYLon3sfOGl5Hi9lc=
github.com/goccy/go-yaml v1.13.5 h1:/Hh9Q3d1Q2T7E8ECUUS7Uh53FBGKLfetvQoSV7kLViU=
github.com/goccy/go-yaml v1.13.5/go.mod h1:IjYwxUiJDoqpx2RmbdjMUceGHZwYLon3sfOGl5Hi9lc=
github.com/goccy/go-yaml v1.13.6 h1:pa3JkBPBseTtfqpG9DiSFhyxNPSpJ0BFa39BlMZE16E=
github.com/goccy/go-yaml v1.13.6/go.mod h1:IjYwxUiJDoqpx2RmbdjMUceGHZwYLon3sfOGl5Hi9lc=
github.com/goccy/go-yaml v1.13.7 h1:5k2i973KptPV1mur30XMXwGepDmskip4gA2zHWzWmOY=
github.com/goccy/go-yaml v1.13.7/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-yaml v1.13.8 h1:ftugzaplJyFaFwfyVNeq1XQOBxmlp8zazmuiobaCXbk=
github.com/goccy/go-yaml v1.13.8/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-yaml v1.13.9 h1:D/LhDa7E5HS/iYxSZzikUSHt1U9q/TeymVBJwodaglc=
github.com/goccy/go-yaml v1.13.9/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-yaml v1.14.0 h1:G/NDXJvf1CX0FshjxKn2AOL0MnrxsSJNpY9FpvMRblw=
github.com/goccy/go-yaml v1.14.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-yaml v1.14.1 h1:NJ9Ch49K/WichY7pAtSvIJbvGjmBDjHVQxuWBbPSOPg=
github.com/goccy/go-yaml v1.14.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-yaml v1.14.2 h1:MzONUP3PM6jnePSNWb2A9fI/xEx1OduPaK/hMC9L9fQ=
github.com/goccy/go-yaml v1.14.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-yaml v1.14.3 h1:8tVD+aqqPLWisSEhM+6wWoiURWXCx6BwaTKS6ZeITgM=
github.com/goccy/go-yaml v1.14.3/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand All @@ -70,24 +23,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 h1:1wqE9dj9NpSm04INVsJhhEUzhuDVjbcyKH91sVyPATw=
golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
4 changes: 4 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var (
tags []string
structNameFromTitle bool
minSizedInts bool
minimalNames bool

errFlagFormat = errors.New("flag must be in the format URI=PACKAGE")

Expand Down Expand Up @@ -77,6 +78,7 @@ var (
Tags: tags,
OnlyModels: onlyModels,
MinSizedInts: minSizedInts,
MinimalNames: minimalNames,
}
for _, id := range allKeys(schemaPackageMap, schemaOutputMap, schemaRootTypeMap) {
mapping := generator.SchemaMapping{SchemaID: id}
Expand Down Expand Up @@ -173,6 +175,8 @@ also look for foo.json if --resolve-extension json is provided.`)
"min-sized-ints",
false,
"Uses sized int and uint values based on the min and max values for the field")
rootCmd.PersistentFlags().BoolVar(&minimalNames, "minimal-names", false,
"Uses the shortest possible names")

abortWithErr(rootCmd.Execute())
}
Expand Down
38 changes: 26 additions & 12 deletions pkg/generator/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,33 @@ package generator
import "github.com/atombender/go-jsonschema/pkg/schemas"

type Config struct {
SchemaMappings []SchemaMapping
ExtraImports bool
Capitalizations []string
ResolveExtensions []string
YAMLExtensions []string
DefaultPackageName string
DefaultOutputName string
SchemaMappings []SchemaMapping
// ExtraImports allows the generator to pull imports from outside the standard library.
ExtraImports bool
// Capitalizations configures capitalized forms for identifiers which take precedence over the default algorithm.
Capitalizations []string
// ResolveExtensions configures file extensions to use when resolving schema names.
ResolveExtensions []string
// YAMLExtensions configures the file extensions that are recognized as YAML files.
YAMLExtensions []string
// DefaultPackageName configures the package to declare files under.
DefaultPackageName string
// DefaultOutputName configures the file to write.
DefaultOutputName string
// StructNameFromTitle configures the generator to use the schema title as the generated struct name.
StructNameFromTitle bool
Warner func(string)
Tags []string
OnlyModels bool
MinSizedInts bool
Loader schemas.Loader
// Warner provides a handler for warning messages.
Warner func(string)
// Tags specifies which struct tags should be generated.
Tags []string
// OnlyModels configures the generator to omit unmarshal methods, validations, anything but models.
OnlyModels bool
// MinSizedInts configures the generator to use the smallest int and uint types based on schema maximum values.
MinSizedInts bool
// MinimalNames configures the generator to use the shortest identifier names possible.
MinimalNames bool
// Loader provides a schema loader for the generator.
Loader schemas.Loader
}

type SchemaMapping struct {
Expand Down
33 changes: 18 additions & 15 deletions pkg/generator/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ var (
)

type Generator struct {
caser *text.Caser
config Config
inScope map[qualifiedDefinition]struct{}
outputs map[string]*output
warner func(string)
formatters []formatter
loader schemas.Loader
caser *text.Caser
config Config
inScope map[qualifiedDefinition]struct{}
outputs map[string]*output
warner func(string)
formatters []formatter
loader schemas.Loader
minimalNames bool
}

type qualifiedDefinition struct {
Expand All @@ -54,13 +55,14 @@ func New(config Config) (*Generator, error) {
}

generator := &Generator{
caser: text.NewCaser(config.Capitalizations, config.ResolveExtensions),
config: config,
inScope: map[qualifiedDefinition]struct{}{},
outputs: map[string]*output{},
warner: config.Warner,
formatters: formatters,
loader: config.Loader,
caser: text.NewCaser(config.Capitalizations, config.ResolveExtensions),
config: config,
inScope: map[qualifiedDefinition]struct{}{},
outputs: map[string]*output{},
warner: config.Warner,
formatters: formatters,
loader: config.Loader,
minimalNames: config.MinimalNames,
}

if config.Loader == nil {
Expand Down Expand Up @@ -199,7 +201,8 @@ func (g *Generator) beginOutput(
}

output := &output{
warner: g.warner,
minimalNames: g.minimalNames,
warner: g.warner,
file: &codegen.File{
FileName: outputName,
Package: pkg,
Expand Down
26 changes: 22 additions & 4 deletions pkg/generator/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,39 @@ import (
)

type output struct {
minimalNames bool
file *codegen.File
declsByName map[string]*codegen.TypeDecl
declsBySchema map[*schemas.Type]*codegen.TypeDecl
warner func(string)
}

func (o *output) uniqueTypeName(name string) string {
v, ok := o.declsByName[name]
// uniqueTypeName finds the shortest identifier in a name scope that yields a unique type name.
// If a given suffix on the name scope is not unique, more context from the scope is added. If the
// entire context does not yield a unique name, a numeric suffix is used.
// TODO: we should check for schema equality on name collisions here to deduplicate identifiers.
func (o *output) uniqueTypeName(scope nameScope) string {
if o.minimalNames {
for i := len(scope) - 1; i >= 0; i-- {
name := scope[i:].string()

v, ok := o.declsByName[name]
if !ok || (ok && v.Type == nil) {
// An identifier using the current amount of name context is unique, use it.
return name
}
}
}

// If we can't make a unique name with the entire context, attempt a numeric suffix.
count := 1
name := scope.string()

v, ok := o.declsByName[name]
if !ok || (ok && v.Type == nil) {
return name
}

count := 1

for {
suffixed := fmt.Sprintf("%s_%d", name, count)
if _, ok := o.declsByName[suffixed]; !ok {
Expand Down
19 changes: 15 additions & 4 deletions pkg/generator/schema_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func (g *schemaGenerator) generateDeclaredType(
}

decl := codegen.TypeDecl{
Name: g.output.uniqueTypeName(scope.string()),
Name: g.output.uniqueTypeName(scope),
Comment: t.Description,
}
g.output.declsBySchema[t] = &decl
Expand Down Expand Up @@ -432,7 +432,7 @@ func (g *schemaGenerator) generateType(
return nil, errArrayPropertyItems
}

elemType, err := g.generateType(t.Items, scope.add("Elem"))
elemType, err := g.generateType(t.Items, g.singularScope(scope))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -764,7 +764,7 @@ func (g *schemaGenerator) generateTypeInline(
} else {
var err error

theType, err = g.generateTypeInline(t.Items, scope.add("Elem"))
theType, err = g.generateTypeInline(t.Items, g.singularScope(scope))
if err != nil {
return nil, err
}
Expand All @@ -777,6 +777,17 @@ func (g *schemaGenerator) generateTypeInline(
return g.generateDeclaredType(t, scope)
}

// singularScope attempts to create a name scope for an element of a collection. If the parent collection
// has a plural name like "Actions", then the singular name for the element will be "Action". If the collection
// is not plural, like "WhateverElse", then the element's name will be "WhateverElseElem".
func (g *Generator) singularScope(scope nameScope) nameScope {
if g.minimalNames && len(scope) > 0 && strings.HasSuffix(scope[len(scope)-1], "s") {
return scope[:len(scope)-1].add(strings.TrimSuffix(scope[len(scope)-1], "s"))
}

return scope.add("Elem")
}

func (g *schemaGenerator) generateEnumType(
t *schemas.Type, scope nameScope,
) (codegen.Type, error) {
Expand Down Expand Up @@ -876,7 +887,7 @@ func (g *schemaGenerator) generateEnumType(
}

enumDecl := codegen.TypeDecl{
Name: g.output.uniqueTypeName(scope.string()),
Name: g.output.uniqueTypeName(scope),
Type: enumType,
}
g.output.file.Package.AddDecl(&enumDecl)
Expand Down
2 changes: 2 additions & 0 deletions tests/data/deeplyNested/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
standalone/RolloutSpecification.json:
wget --output-document=$@ --quiet https://ev2schema.azure.net/schemas/2020-01-01/$(notdir $@)
Loading