Skip to content

Instantly share code, notes, and snippets.

@axw
Created August 10, 2016 03:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save axw/0d395b86aa5ac9ee0c4f18a3ca81cb68 to your computer and use it in GitHub Desktop.
Save axw/0d395b86aa5ac9ee0c4f18a3ca81cb68 to your computer and use it in GitHub Desktop.
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