| 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