Compare commits

..

No commits in common. "e0d73b537145d4ab0efb771b82f0c16fc99fc033" and "3252e0dde7feaa4fa8fb57f9c57f0909b850b271" have entirely different histories.

3 changed files with 7 additions and 93 deletions

View file

@ -1,31 +1,11 @@
# go-jsonschema # go-jsonschema
A [JSON schema] code generator for Go. A JSON schema code generator for Go.
JSON schema draft 2020-12 is supported.
## Usage ## Usage
jsonschemagen -s <schema> -o <output> jsonschemagen -s <schema> -o <output>
One Go type per definition will be generated.
- `int64` is used for `"type": "integer"`.
- `json.Number` is used for `"type": "number"`.
- Go structs are generated for objects with `"additionalProperties": false`.
- `json.RawMessage` is used when a value can have multiple types. Helpers are
generated for `allOf`, `anyOf`, `oneOf`, `then`, `else` and `dependantSchemas`
which are references.
## Contributing
Report bugs and send patches to the [mailing list]. Discuss in [#emersion] on
Libera Chat.
## License ## License
MIT MIT
[JSON schema]: https://json-schema.org/
[mailing list]: https://lists.sr.ht/~emersion/public-inbox
[#emersion]: ircs://irc.libera.chat/#emersion

View file

@ -52,11 +52,8 @@ func resolveRef(def *jsonschema.Schema, root *jsonschema.Schema) *jsonschema.Sch
} }
func schemaType(schema *jsonschema.Schema) jsonschema.Type { func schemaType(schema *jsonschema.Schema) jsonschema.Type {
switch { if schema.Type != "" {
case len(schema.Type) == 1: return schema.Type
return schema.Type[0]
case len(schema.Type) > 0:
return ""
} }
var v interface{} var v interface{}
@ -128,40 +125,9 @@ func noAdditionalProps(schema *jsonschema.Schema) bool {
return schema.AdditionalProperties != nil && schema.AdditionalProperties.IsFalse() return schema.AdditionalProperties != nil && schema.AdditionalProperties.IsFalse()
} }
// unwrapNullableSchema unwraps a schema in the form:
//
// {
// "oneOf": {
// { "type": "null" },
// <sub-schema>
// }
// }
func unwrapNullableSchema(schema *jsonschema.Schema) (*jsonschema.Schema, bool) {
for _, choices := range [][]jsonschema.Schema{schema.AnyOf, schema.OneOf} {
if len(choices) != 2 {
continue
}
nullIndex := -1
for i, choice := range choices {
if len(choice.Type) == 1 && choice.Type[0] == jsonschema.TypeNull {
nullIndex = i
break
}
}
if nullIndex < 0 {
continue
}
otherIndex := (nullIndex + 1) % 2
return &choices[otherIndex], true
}
return nil, false
}
func generateSchemaType(schema *jsonschema.Schema, root *jsonschema.Schema, required bool) jen.Code { func generateSchemaType(schema *jsonschema.Schema, root *jsonschema.Schema, required bool) jen.Code {
if schema == nil { if schema == nil {
schema = &jsonschema.Schema{} return jen.Interface()
} }
refName := refName(schema.Ref) refName := refName(schema.Ref)
@ -174,10 +140,6 @@ func generateSchemaType(schema *jsonschema.Schema, root *jsonschema.Schema, requ
return t return t
} }
if subschema, ok := unwrapNullableSchema(schema); ok {
return jen.Op("*").Add(generateSchemaType(subschema, root, true))
}
switch schemaType(schema) { switch schemaType(schema) {
case jsonschema.TypeNull: case jsonschema.TypeNull:
return jen.Struct() return jen.Struct()
@ -186,7 +148,7 @@ func generateSchemaType(schema *jsonschema.Schema, root *jsonschema.Schema, requ
case jsonschema.TypeArray: case jsonschema.TypeArray:
return jen.Index().Add(generateSchemaType(schema.Items, root, required)) return jen.Index().Add(generateSchemaType(schema.Items, root, required))
case jsonschema.TypeNumber: case jsonschema.TypeNumber:
return jen.Qual("encoding/json", "Number") return jen.Float64()
case jsonschema.TypeString: case jsonschema.TypeString:
return jen.String() return jen.String()
case jsonschema.TypeInteger: case jsonschema.TypeInteger:
@ -227,15 +189,6 @@ func generateDef(schema *jsonschema.Schema, root *jsonschema.Schema, f *jen.File
for _, child := range schema.OneOf { for _, child := range schema.OneOf {
children = append(children, child) children = append(children, child)
} }
if schema.Then != nil {
children = append(children, *schema.Then)
}
if schema.Else != nil {
children = append(children, *schema.Else)
}
for _, child := range schema.DependentSchemas {
children = append(children, child)
}
for _, child := range children { for _, child := range children {
refName := refName(child.Ref) refName := refName(child.Ref)

View file

@ -17,25 +17,6 @@ const (
TypeInteger Type = "integer" TypeInteger Type = "integer"
) )
type TypeSet []Type
func (ts *TypeSet) UnmarshalJSON(b []byte) error {
if b[0] == '[' {
type rawTypeSet TypeSet
out := (*rawTypeSet)(ts)
return json.Unmarshal(b, out)
} else {
var t Type
err := json.Unmarshal(b, &t)
if err != nil {
*ts = nil
} else {
*ts = []Type{t}
}
return err
}
}
type Schema struct { type Schema struct {
// Core // Core
Schema string `json:"$schema"` Schema string `json:"$schema"`
@ -70,7 +51,7 @@ type Schema struct {
PropertyNames *Schema `json:"propertyNames"` PropertyNames *Schema `json:"propertyNames"`
// Validation // Validation
Type TypeSet `json:"type"` Type Type `json:"type"`
Enum []interface{} `json:"enum"` Enum []interface{} `json:"enum"`
Const interface{} `json:"const"` Const interface{} `json:"const"`
@ -111,7 +92,7 @@ type Schema struct {
func (schema *Schema) UnmarshalJSON(b []byte) error { func (schema *Schema) UnmarshalJSON(b []byte) error {
if bytes.Equal(b, []byte("true")) { if bytes.Equal(b, []byte("true")) {
*schema = Schema{} // Nothing to do
} else if bytes.Equal(b, []byte("false")) { } else if bytes.Equal(b, []byte("false")) {
*schema = Schema{Not: []Schema{ *schema = Schema{Not: []Schema{
Schema{}, Schema{},