Skip to content

Commit

Permalink
add an option to allow to generate only models
Browse files Browse the repository at this point in the history
  • Loading branch information
AlbertoBarba committed Oct 1, 2023
1 parent 5df46e1 commit e5167ff
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 41 deletions.
4 changes: 4 additions & 0 deletions cmd/gojsonschema/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
var (
verbose bool
extraImports bool
onlyModels bool
defaultPackage string
defaultOutput string
schemaPackages []string
Expand Down Expand Up @@ -73,6 +74,7 @@ var (
YAMLExtensions: yamlExtensions,
StructNameFromTitle: structNameFromTitle,
Tags: tags,
OnlyModels: onlyModels,
}
for _, id := range allKeys(schemaPackageMap, schemaOutputMap, schemaRootTypeMap) {
mapping := generator.SchemaMapping{SchemaID: id}
Expand Down Expand Up @@ -136,6 +138,8 @@ func main() {
"Verbose output")
rootCmd.PersistentFlags().BoolVarP(&extraImports, "extra-imports", "e", false,
"Allow extra imports (non standard library)")
rootCmd.PersistentFlags().BoolVar(&onlyModels, "only-models", false,
"Generate only models (no unmarshal methods, no validation)")
rootCmd.PersistentFlags().StringVarP(&defaultPackage, "package", "p", "",
`Default name of package to declare Go files under, unless overridden with
--schema-package`)
Expand Down
88 changes: 47 additions & 41 deletions pkg/generator/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Config struct {
StructNameFromTitle bool
Warner func(string)
Tags []string
OnlyModels bool
}

type SchemaMapping struct {
Expand Down Expand Up @@ -545,6 +546,10 @@ func (g *schemaGenerator) generateDeclaredType(

g.output.file.Package.AddDecl(&decl)

if g.config.OnlyModels {
return &codegen.NamedType{Decl: &decl}, nil
}

if structType, ok := theType.(*codegen.StructType); ok {
var validators []validator
for _, f := range structType.RequiredJSONFields {
Expand Down Expand Up @@ -1064,57 +1069,58 @@ func (g *schemaGenerator) generateEnumType(
g.output.declsByName[enumDecl.Name] = &enumDecl
g.output.declsBySchema[t] = &enumDecl

valueConstant := &codegen.Var{
Name: "enumValues_" + enumDecl.Name,
Value: t.Enum,
}
g.output.file.Package.AddDecl(valueConstant)
if !g.config.OnlyModels {
valueConstant := &codegen.Var{
Name: "enumValues_" + enumDecl.Name,
Value: t.Enum,
}
g.output.file.Package.AddDecl(valueConstant)

if wrapInStruct {
if wrapInStruct {
g.output.file.Package.AddImport("encoding/json", "")
g.output.file.Package.AddDecl(&codegen.Method{
Impl: func(out *codegen.Emitter) {
out.Comment("MarshalJSON implements json.Marshaler.")
out.Printlnf("func (j *%s) MarshalJSON() ([]byte, error) {", enumDecl.Name)
out.Indent(1)
out.Printlnf("return json.Marshal(j.Value)")
out.Indent(-1)
out.Printlnf("}")
},
})
}

g.output.file.Package.AddImport("fmt", "")
g.output.file.Package.AddImport("reflect", "")
g.output.file.Package.AddImport("encoding/json", "")
g.output.file.Package.AddDecl(&codegen.Method{
Impl: func(out *codegen.Emitter) {
out.Comment("MarshalJSON implements json.Marshaler.")
out.Printlnf("func (j *%s) MarshalJSON() ([]byte, error) {", enumDecl.Name)
out.Comment("UnmarshalJSON implements json.Unmarshaler.")
out.Printlnf("func (j *%s) UnmarshalJSON(b []byte) error {", enumDecl.Name)
out.Indent(1)
out.Printlnf("return json.Marshal(j.Value)")
out.Printf("var v ")
enumType.Generate(out)
out.Newline()
varName := "v"
if wrapInStruct {
varName += ".Value"
}
out.Printlnf("if err := json.Unmarshal(b, &%s); err != nil { return err }", varName)
out.Printlnf("var ok bool")
out.Printlnf("for _, expected := range %s {", valueConstant.Name)
out.Printlnf("if reflect.DeepEqual(%s, expected) { ok = true; break }", varName)
out.Printlnf("}")
out.Printlnf("if !ok {")
out.Printlnf(`return fmt.Errorf("invalid value (expected one of %%#v): %%#v", %s, %s)`,
valueConstant.Name, varName)
out.Printlnf("}")
out.Printlnf(`*j = %s(v)`, enumDecl.Name)
out.Printlnf(`return nil`)
out.Indent(-1)
out.Printlnf("}")
},
})
}

g.output.file.Package.AddImport("fmt", "")
g.output.file.Package.AddImport("reflect", "")
g.output.file.Package.AddImport("encoding/json", "")
g.output.file.Package.AddDecl(&codegen.Method{
Impl: func(out *codegen.Emitter) {
out.Comment("UnmarshalJSON implements json.Unmarshaler.")
out.Printlnf("func (j *%s) UnmarshalJSON(b []byte) error {", enumDecl.Name)
out.Indent(1)
out.Printf("var v ")
enumType.Generate(out)
out.Newline()
varName := "v"
if wrapInStruct {
varName += ".Value"
}
out.Printlnf("if err := json.Unmarshal(b, &%s); err != nil { return err }", varName)
out.Printlnf("var ok bool")
out.Printlnf("for _, expected := range %s {", valueConstant.Name)
out.Printlnf("if reflect.DeepEqual(%s, expected) { ok = true; break }", varName)
out.Printlnf("}")
out.Printlnf("if !ok {")
out.Printlnf(`return fmt.Errorf("invalid value (expected one of %%#v): %%#v", %s, %s)`,
valueConstant.Name, varName)
out.Printlnf("}")
out.Printlnf(`*j = %s(v)`, enumDecl.Name)
out.Printlnf(`return nil`)
out.Indent(-1)
out.Printlnf("}")
},
})

// TODO: May be aliased string type.
if prim, ok := enumType.(codegen.PrimitiveType); ok && prim.Type == "string" {
for _, v := range t.Enum {
Expand Down
28 changes: 28 additions & 0 deletions tests/data/onlyModels/onlyModel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions tests/data/onlyModels/onlyModel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "https://example.com/primitives",
"type": "object",
"properties": {
"myString": {
"type": "string"
},
"myNumber": {
"type": "number"
},
"myInteger": {
"type": "integer"
},
"myBoolean": {
"type": "boolean"
},
"myNull": {
"type": "null"
},
"myEnum": {
"type": "string",
"enum": [
"x",
"y"
]
}
}
}
9 changes: 9 additions & 0 deletions tests/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,15 @@ func TestRegressions(t *testing.T) {
testExamples(t, basicConfig, "./data/regressions")
}

func TestOnlyModels(t *testing.T) {
t.Parallel()

cfg := basicConfig
cfg.OnlyModels = true

testExamples(t, cfg, "./data/onlyModels")
}

func testExampleFile(t *testing.T, cfg generator.Config, fileName string) {
t.Helper()

Expand Down

0 comments on commit e5167ff

Please sign in to comment.