Compare commits
No commits in common. "e0d73b537145d4ab0efb771b82f0c16fc99fc033" and "3252e0dde7feaa4fa8fb57f9c57f0909b850b271" have entirely different histories.
e0d73b5371
...
3252e0dde7
3 changed files with 7 additions and 93 deletions
22
README.md
22
README.md
|
@ -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
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
23
schema.go
23
schema.go
|
@ -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{},
|
||||||
|
|
Loading…
Reference in a new issue