@@ -13,6 +13,14 @@ import (
1313 "github.com/atombender/go-jsonschema/pkg/schemas"
1414)
1515
16+ type Config struct {
17+ SchemaMappings []SchemaMapping
18+ Capitalizations []string
19+ DefaultPackageName string
20+ DefaultOutputName string
21+ Warner func (string )
22+ }
23+
1624type SchemaMapping struct {
1725 SchemaID string
1826 PackageName string
@@ -21,25 +29,15 @@ type SchemaMapping struct {
2129}
2230
2331type Generator struct {
32+ config Config
2433 emitter * codegen.Emitter
25- defaultPackageName string
26- defaultOutputName string
27- schemaMappings []SchemaMapping
28- warner func (string )
2934 outputs map [string ]* output
3035 schemaCacheByFileName map [string ]* schemas.Schema
3136}
3237
33- func New (
34- schemaMappings []SchemaMapping ,
35- defaultPackageName string ,
36- defaultOutputName string ,
37- warner func (string )) (* Generator , error ) {
38+ func New (config Config ) (* Generator , error ) {
3839 return & Generator {
39- warner : warner ,
40- schemaMappings : schemaMappings ,
41- defaultPackageName : defaultPackageName ,
42- defaultOutputName : defaultOutputName ,
40+ config : config ,
4341 outputs : map [string ]* output {},
4442 schemaCacheByFileName : map [string ]* schemas.Schema {},
4543 }, nil
@@ -123,25 +121,25 @@ func (g *Generator) loadSchemaFromFile(fileName, parentFileName string) (*schema
123121}
124122
125123func (g * Generator ) getRootTypeName (schema * schemas.Schema , fileName string ) string {
126- for _ , m := range g .schemaMappings {
124+ for _ , m := range g .config . SchemaMappings {
127125 if m .SchemaID == schema .ID && m .RootType != "" {
128126 return m .RootType
129127 }
130128 }
131- return codegen . IdentifierFromFileName (fileName )
129+ return g . identifierFromFileName (fileName )
132130}
133131
134132func (g * Generator ) findOutputFileForSchemaID (id string ) (* output , error ) {
135133 if o , ok := g .outputs [id ]; ok {
136134 return o , nil
137135 }
138136
139- for _ , m := range g .schemaMappings {
137+ for _ , m := range g .config . SchemaMappings {
140138 if m .SchemaID == id {
141139 return g .beginOutput (id , m .OutputName , m .PackageName )
142140 }
143141 }
144- return g .beginOutput (id , g .defaultOutputName , g .defaultPackageName )
142+ return g .beginOutput (id , g .config . DefaultOutputName , g .config . DefaultPackageName )
145143}
146144
147145func (g * Generator ) beginOutput (
@@ -170,7 +168,7 @@ func (g *Generator) beginOutput(
170168 }
171169
172170 output := & output {
173- warner : g .warner ,
171+ warner : g .config . Warner ,
174172 file : & codegen.File {
175173 FileName : outputName ,
176174 Package : pkg ,
@@ -183,6 +181,39 @@ func (g *Generator) beginOutput(
183181 return output , nil
184182}
185183
184+ func (g * Generator ) makeEnumConstantName (typeName , value string ) string {
185+ if strings .ContainsAny (typeName [len (typeName )- 1 :], "0123456789" ) {
186+ return typeName + "_" + g .identifierize (value )
187+ }
188+ return typeName + g .identifierize (value )
189+ }
190+
191+ func (g * Generator ) identifierFromFileName (fileName string ) string {
192+ s := filepath .Base (fileName )
193+ return g .identifierize (strings .TrimSuffix (strings .TrimSuffix (s , ".json" ), ".schema" ))
194+ }
195+
196+ func (g * Generator ) identifierize (s string ) string {
197+ // FIXME: Better handling of non-identifier chars
198+ var sb strings.Builder
199+ for _ , part := range splitIdentifierByCaseAndSeparators (s ) {
200+ _ , _ = sb .WriteString (g .capitalize (part ))
201+ }
202+ return sb .String ()
203+ }
204+
205+ func (g * Generator ) capitalize (s string ) string {
206+ if len (s ) == 0 {
207+ return ""
208+ }
209+ for _ , c := range g .config .Capitalizations {
210+ if strings .ToLower (c ) == strings .ToLower (s ) {
211+ return c
212+ }
213+ }
214+ return strings .ToUpper (s [0 :1 ]) + s [1 :]
215+ }
216+
186217type schemaGenerator struct {
187218 * Generator
188219 output * output
@@ -197,7 +228,7 @@ func (g *schemaGenerator) generateRootType() error {
197228
198229 if g .schema .Type .Type == "" {
199230 for name , def := range g .schema .Definitions {
200- _ , err := g .generateDeclaredType (def , newNameScope (codegen . Identifierize (name )))
231+ _ , err := g .generateDeclaredType (def , newNameScope (g . identifierize (name )))
201232 if err != nil {
202233 return err
203234 }
@@ -250,7 +281,7 @@ func (g *schemaGenerator) generateReferencedType(ref string) (codegen.Type, erro
250281 }
251282 // Minor hack to make definitions default to being objects
252283 def .Type = schemas .TypeNameObject
253- defName = codegen . Identifierize (defName )
284+ defName = g . identifierize (defName )
254285 } else {
255286 def = schema .Type
256287 defName = g .getRootTypeName (schema , fileName )
@@ -423,7 +454,7 @@ func (g *schemaGenerator) generateStructType(
423454 scope nameScope ) (codegen.Type , error ) {
424455 if len (t .Properties ) == 0 {
425456 if len (t .Required ) > 0 {
426- g .warner ("object type with no properties has required fields; " +
457+ g .config . Warner ("object type with no properties has required fields; " +
427458 "skipping validation code for them since we don't know their types" )
428459 }
429460 return & codegen.MapType {
@@ -450,11 +481,11 @@ func (g *schemaGenerator) generateStructType(
450481 prop := t .Properties [name ]
451482 isRequired := requiredNames [name ]
452483
453- fieldName := codegen . Identifierize (name )
484+ fieldName := g . identifierize (name )
454485 if count , ok := uniqueNames [fieldName ]; ok {
455486 uniqueNames [fieldName ] = count + 1
456487 fieldName = fmt .Sprintf ("%s_%d" , fieldName , count + 1 )
457- g .warner (fmt .Sprintf ("field %q maps to a field by the same name declared " +
488+ g .config . Warner (fmt .Sprintf ("field %q maps to a field by the same name declared " +
458489 "in the same struct; it will be declared as %s" , name , fieldName ))
459490 } else {
460491 uniqueNames [fieldName ] = 1
@@ -575,7 +606,7 @@ func (g *schemaGenerator) generateEnumType(
575606 enumType = codegen.PrimitiveType {primitiveType }
576607 }
577608 if wrapInStruct {
578- g .warner ("Enum field wrapped in struct in order to store values of multiple types" )
609+ g .config . Warner ("Enum field wrapped in struct in order to store values of multiple types" )
579610 enumType = & codegen.StructType {
580611 Fields : []codegen.StructField {
581612 {
@@ -659,7 +690,7 @@ func (g *schemaGenerator) generateEnumType(
659690 if s , ok := v .(string ); ok {
660691 // TODO: Make sure the name is unique across scope
661692 g .output .file .Package .AddDecl (& codegen.Constant {
662- Name : makeEnumConstantName (enumDecl .Name , s ),
693+ Name : g . makeEnumConstantName (enumDecl .Name , s ),
663694 Type : & codegen.NamedType {Decl : & enumDecl },
664695 Value : s ,
665696 })
@@ -670,24 +701,6 @@ func (g *schemaGenerator) generateEnumType(
670701 return & codegen.NamedType {Decl : & enumDecl }, nil
671702}
672703
673- // func (g *schemaGenerator) generateAnonymousType(
674- // t *schemas.Type, name string) (codegen.Type, error) {
675- // if t.Type == schemas.TypeNameObject {
676- // if len(t.Properties) == 0 {
677- // return codegen.MapType{
678- // KeyType: codegen.PrimitiveType{"string"},
679- // ValueType: codegen.EmptyInterfaceType{},
680- // }, nil
681- // }
682- // s, err := g.generateStructDecl(t, name, "", false)
683- // if err != nil {
684- // return nil, err
685- // }
686- // return &codegen.NamedType{Decl: s}, nil
687- // }
688- // return nil, fmt.Errorf("unexpected type %q", t.Type)
689- // }
690-
691704type output struct {
692705 file * codegen.File
693706 enums map [string ]cachedEnum
0 commit comments