json: pass to clean up objcet lists

This commit is contained in:
Mitchell Hashimoto 2015-11-07 16:34:47 -08:00
parent 60534579be
commit e3ed2553ca
2 changed files with 79 additions and 35 deletions

View File

@ -159,7 +159,7 @@ func TestDecode_interface(t *testing.T) {
"structure_list.json",
false,
map[string]interface{}{
"foo": []interface{}{
"foo": []map[string]interface{}{
map[string]interface{}{
"key": 7,
},

View File

@ -65,24 +65,78 @@ func flattenObjects(node ast.Node) {
item := frontier[n-1]
frontier = frontier[:n-1]
// We only care if the value of this item is an object
ot, ok := item.Val.(*ast.ObjectType)
if !ok {
switch v := item.Val.(type) {
case *ast.ObjectType:
items, frontier = flattenObjectType(v, item, items, frontier)
case *ast.ListType:
items, frontier = flattenListType(v, item, items, frontier)
default:
items = append(items, item)
continue
}
}
// Reverse the list since the frontier model runs things backwards
for i := len(items)/2 - 1; i >= 0; i-- {
opp := len(items) - 1 - i
items[i], items[opp] = items[opp], items[i]
}
// Done! Set the original items
list.Items = items
return true
})
}
func flattenListType(
ot *ast.ListType,
item *ast.ObjectItem,
items []*ast.ObjectItem,
frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
// All the elements of this object must also be objects!
match := true
for _, item := range ot.List.Items {
if _, ok := item.Val.(*ast.ObjectType); !ok {
match = false
break
}
}
if !match {
for _, subitem := range ot.List {
if _, ok := subitem.(*ast.ObjectType); !ok {
items = append(items, item)
continue
return items, frontier
}
}
// Great! We have a match go through all the items and flatten
for _, elem := range ot.List {
// This won't fail since we verified it earlier
ot := elem.(*ast.ObjectType)
// Go over all the subitems and merge them in
for _, subitem := range ot.List.Items {
// Copy the new key
keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys))
copy(keys, item.Keys)
copy(keys[len(item.Keys):], subitem.Keys)
// Add it to the frontier so that we can recurse
frontier = append(frontier, &ast.ObjectItem{
Keys: keys,
Assign: item.Assign,
Val: subitem.Val,
LeadComment: item.LeadComment,
LineComment: item.LineComment,
})
}
}
return items, frontier
}
func flattenObjectType(
ot *ast.ObjectType,
item *ast.ObjectItem,
items []*ast.ObjectItem,
frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
// All the elements of this object must also be objects!
for _, subitem := range ot.List.Items {
if _, ok := subitem.Val.(*ast.ObjectType); !ok {
items = append(items, item)
return items, frontier
}
}
// Great! We have a match go through all the items and flatten
@ -101,16 +155,6 @@ func flattenObjects(node ast.Node) {
LineComment: item.LineComment,
})
}
}
// Reverse the list since the frontier model runs things backwards
for i := len(items)/2 - 1; i >= 0; i-- {
opp := len(items) - 1 - i
items[i], items[opp] = items[opp], items[i]
}
// Done! Set the original items
list.Items = items
return true
})
return items, frontier
}