Created
August 10, 2016 03:19
-
-
Save axw/0d395b86aa5ac9ee0c4f18a3ca81cb68 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"io" | |
"regexp" | |
"strings" | |
"github.com/lestrrat/go-jsschema" | |
) | |
const example = ` | |
{ | |
"type": "object", | |
"properties": { | |
"payload": { | |
"type": "string", | |
"minLength": 5, | |
"maxLength": 10, | |
"secret": true | |
} | |
}, | |
"immutable": true | |
} | |
` | |
type SchemaList []*Schema | |
type Schema struct { | |
ID string | |
Title string | |
Description string | |
Default interface{} | |
Type schema.PrimitiveTypes | |
SchemaRef string | |
Definitions map[string]*Schema | |
Reference string | |
Format schema.Format | |
// NumericValidations | |
MultipleOf schema.Number | |
Minimum schema.Number | |
Maximum schema.Number | |
ExclusiveMinimum schema.Bool | |
ExclusiveMaximum schema.Bool | |
// StringValidation | |
MaxLength schema.Integer | |
MinLength schema.Integer | |
Pattern *regexp.Regexp | |
// ArrayValidations | |
AdditionalItems *AdditionalItems | |
Items *ItemSpec | |
MinItems schema.Integer | |
MaxItems schema.Integer | |
UniqueItems schema.Bool | |
// ObjectValidations | |
MaxProperties schema.Integer | |
MinProperties schema.Integer | |
Required []string | |
Dependencies DependencyMap | |
Properties map[string]*Schema | |
AdditionalProperties *AdditionalProperties | |
PatternProperties map[*regexp.Regexp]*Schema | |
Enum []interface{} | |
AllOf SchemaList | |
AnyOf SchemaList | |
OneOf SchemaList | |
Not *Schema | |
// Juju-specific properties. | |
Secret bool | |
Immutable bool | |
} | |
type AdditionalItems struct { | |
*Schema | |
} | |
type AdditionalProperties struct { | |
*Schema | |
} | |
// DependencyMap contains the dependencies defined within this schema. | |
// for a given dependency name, you can have either a schema or a | |
// list of property names | |
type DependencyMap struct { | |
Names map[string][]string | |
Schemas map[string]*Schema | |
} | |
type ItemSpec struct { | |
TupleMode bool | |
Schemas SchemaList | |
} | |
func readSchema(r io.Reader) (*Schema, error) { | |
internalSchema, err := schema.Read(r) | |
if err != nil { | |
return nil, err | |
} | |
cache := make(map[*schema.Schema]*Schema) | |
return fromInternal(internalSchema, cache) | |
} | |
func fromInternalSchemaList(in schema.SchemaList, cache map[*schema.Schema]*Schema) (SchemaList, error) { | |
list := make(SchemaList, len(in)) | |
for i, in := range in { | |
out, err := fromInternal(in, cache) | |
if err != nil { | |
return nil, err | |
} | |
list[i] = out | |
} | |
return list, nil | |
} | |
func fromInternalSchemaMap(in map[string]*schema.Schema, cache map[*schema.Schema]*Schema) (map[string]*Schema, error) { | |
m := make(map[string]*Schema) | |
for k, in := range in { | |
out, err := fromInternal(in, cache) | |
if err != nil { | |
return nil, err | |
} | |
m[k] = out | |
} | |
return m, nil | |
} | |
func fromInternal(in *schema.Schema, cache map[*schema.Schema]*Schema) (*Schema, error) { | |
if in == nil { | |
return nil, nil | |
} | |
if out, ok := cache[in]; ok { | |
return out, nil | |
} | |
out := &Schema{} | |
cache[in] = out | |
definitions := make(map[string]*Schema) | |
for k, in := range in.Definitions { | |
out, err := fromInternal(in, cache) | |
if err != nil { | |
return nil, err | |
} | |
definitions[k] = out | |
} | |
var additionalItems *AdditionalItems | |
if in.AdditionalItems != nil { | |
out, err := fromInternal(in.AdditionalItems.Schema, cache) | |
if err != nil { | |
return nil, err | |
} | |
additionalItems = &AdditionalItems{out} | |
} | |
var items *ItemSpec | |
if in.Items != nil { | |
schemas, err := fromInternalSchemaList(in.Items.Schemas, cache) | |
if err != nil { | |
return nil, err | |
} | |
items = &ItemSpec{ | |
TupleMode: in.Items.TupleMode, | |
Schemas: schemas, | |
} | |
} | |
schemas, err := fromInternalSchemaMap(in.Dependencies.Schemas, cache) | |
if err != nil { | |
return nil, err | |
} | |
dependencies := DependencyMap{ | |
Names: in.Dependencies.Names, | |
Schemas: schemas, | |
} | |
properties, err := fromInternalSchemaMap(in.Properties, cache) | |
if err != nil { | |
return nil, err | |
} | |
var additionalProperties *AdditionalProperties | |
if in.AdditionalProperties != nil { | |
out, err := fromInternal(in.AdditionalProperties.Schema, cache) | |
if err != nil { | |
return nil, err | |
} | |
additionalProperties = &AdditionalProperties{out} | |
} | |
var patternProperties map[*regexp.Regexp]*Schema | |
if in.PatternProperties != nil { | |
patternProperties = make(map[*regexp.Regexp]*Schema) | |
for re, in := range in.PatternProperties { | |
out, err := fromInternal(in, cache) | |
if err != nil { | |
return nil, err | |
} | |
patternProperties[re] = out | |
} | |
} | |
allOf, err := fromInternalSchemaList(in.AllOf, cache) | |
if err != nil { | |
return nil, err | |
} | |
anyOf, err := fromInternalSchemaList(in.AnyOf, cache) | |
if err != nil { | |
return nil, err | |
} | |
oneOf, err := fromInternalSchemaList(in.OneOf, cache) | |
if err != nil { | |
return nil, err | |
} | |
not, err := fromInternal(in.Not, cache) | |
if err != nil { | |
return nil, err | |
} | |
*out = Schema{ | |
ID: in.ID, | |
Title: in.Title, | |
Description: in.Description, | |
Default: in.Default, | |
Type: in.Type, | |
SchemaRef: in.SchemaRef, | |
Definitions: definitions, | |
Reference: in.Reference, | |
Format: in.Format, | |
MultipleOf: in.MultipleOf, | |
Minimum: in.Minimum, | |
Maximum: in.Maximum, | |
ExclusiveMinimum: in.ExclusiveMinimum, | |
ExclusiveMaximum: in.ExclusiveMaximum, | |
MaxLength: in.MaxLength, | |
MinLength: in.MinLength, | |
Pattern: in.Pattern, | |
AdditionalItems: additionalItems, | |
Items: items, | |
MinItems: in.MinItems, | |
MaxItems: in.MaxItems, | |
UniqueItems: in.UniqueItems, | |
MaxProperties: in.MaxProperties, | |
MinProperties: in.MinProperties, | |
Required: in.Required, | |
Dependencies: dependencies, | |
Properties: properties, | |
AdditionalProperties: additionalProperties, | |
PatternProperties: patternProperties, | |
Enum: in.Enum, | |
AllOf: allOf, | |
AnyOf: anyOf, | |
OneOf: oneOf, | |
Not: not, | |
} | |
// Extract the Juju-specific properties. | |
if secret, ok := in.Extras["secret"]; ok { | |
// TODO error if it's not a bool. | |
out.Secret = secret.(bool) | |
} | |
if immutable, ok := in.Extras["immutable"]; ok { | |
// TODO error if it's not a bool. | |
out.Immutable = immutable.(bool) | |
} | |
return out, nil | |
} | |
func main() { | |
s, err := readSchema(strings.NewReader(example)) | |
if err != nil { | |
panic(err) | |
} | |
fmt.Printf("%+v\n", s) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment