1
// Author: Bodie Solomon
2
// bodie@synapsegarden.net
3
// github.com/binary132
14
// InsertDefaults takes a map[string]interface{} and inserts any missing
15
// default values specified in the JSON-Schema document. If the given "into"
16
// map is nil, it will be created.
18
// This is an initial implementation which does not support refs, etc.
19
// The schema must be for an object, not a bare value.
20
func (s *Schema) InsertDefaults(into map[string]interface{}) (m map[string]interface{}, returnErr error) {
21
// Handle any panics caused by malformed schemas.
22
defer schemaPanicHandler(&returnErr)
24
properties := s.getDocProperties()
26
// Make sure the "into" map isn't nil.
28
into = make(map[string]interface{})
31
// Now insert the default values at the keys in the "into" map,
33
iterateAndInsert(into, properties)
38
// schemaPanics catches panics caused by type assertions or gets on schemas
39
// which have somehow slipped past validation.
40
func schemaPanicHandler(err *error) {
41
if r := recover(); r != nil {
43
switch t := r.(type) {
45
msg = fmt.Sprintf("schema error caused a panic: %s", t.Error())
47
msg = fmt.Sprintf("unknown panic: %#v", t)
49
*err = errors.New(msg)
53
// getDocProperties retrieves the "properties" key of the standalone doc of
56
// Malformed schemas cause a panic.
57
func (s *Schema) getDocProperties() map[string]interface{} {
58
f := s.pool.GetStandaloneDocument()
60
// We need a map[string]interface because we have to check for a
62
docMap := f.(map[string]interface{})
64
// We need a schema with properties, since this feature does not
65
// support raw value schemas.
66
m := docMap["properties"]
68
return m.(map[string]interface{})
71
// iterateAndInsert takes a target map and inserts any missing default values
72
// as specified in the properties map, according to JSON-Schema.
74
// Malformed schemas cause a panic.
75
func iterateAndInsert(into, properties map[string]interface{}) {
76
for property, schema := range properties {
77
// Iterate over each key of the schema. Each key should have
78
// a schema describing the key's properties. If it does not,
80
typedSchema := schema.(map[string]interface{})
82
if v, ok := into[property]; ok {
83
// If there is already a map value in the target for
84
// this key, don't overwrite it; step in. Ignore
86
if innerMap, ok := v.(map[string]interface{}); ok {
87
// The schema should have an inner
88
// schema since it's an object
89
schemaProperties := typedSchema["properties"]
90
typedProperties := schemaProperties.(map[string]interface{})
91
iterateAndInsert(innerMap, typedProperties)
96
if d, ok := typedSchema["default"]; ok {
97
// Most basic case: we have a default value. Done for
103
if p, ok := typedSchema["properties"]; ok {
104
// If we have a "properties" key, this is an object,
105
// and we need to go deeper.
106
innerSchema := p.(map[string]interface{})
107
tmpTarget := make(map[string]interface{})
108
iterateAndInsert(tmpTarget, innerSchema)
109
if len(tmpTarget) > 0 {
110
into[property] = tmpTarget