http urls monitor.

flatten.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package parser
  2. import "github.com/hashicorp/hcl/hcl/ast"
  3. // flattenObjects takes an AST node, walks it, and flattens
  4. func flattenObjects(node ast.Node) {
  5. ast.Walk(node, func(n ast.Node) (ast.Node, bool) {
  6. // We only care about lists, because this is what we modify
  7. list, ok := n.(*ast.ObjectList)
  8. if !ok {
  9. return n, true
  10. }
  11. // Rebuild the item list
  12. items := make([]*ast.ObjectItem, 0, len(list.Items))
  13. frontier := make([]*ast.ObjectItem, len(list.Items))
  14. copy(frontier, list.Items)
  15. for len(frontier) > 0 {
  16. // Pop the current item
  17. n := len(frontier)
  18. item := frontier[n-1]
  19. frontier = frontier[:n-1]
  20. switch v := item.Val.(type) {
  21. case *ast.ObjectType:
  22. items, frontier = flattenObjectType(v, item, items, frontier)
  23. case *ast.ListType:
  24. items, frontier = flattenListType(v, item, items, frontier)
  25. default:
  26. items = append(items, item)
  27. }
  28. }
  29. // Reverse the list since the frontier model runs things backwards
  30. for i := len(items)/2 - 1; i >= 0; i-- {
  31. opp := len(items) - 1 - i
  32. items[i], items[opp] = items[opp], items[i]
  33. }
  34. // Done! Set the original items
  35. list.Items = items
  36. return n, true
  37. })
  38. }
  39. func flattenListType(
  40. ot *ast.ListType,
  41. item *ast.ObjectItem,
  42. items []*ast.ObjectItem,
  43. frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
  44. // If the list is empty, keep the original list
  45. if len(ot.List) == 0 {
  46. items = append(items, item)
  47. return items, frontier
  48. }
  49. // All the elements of this object must also be objects!
  50. for _, subitem := range ot.List {
  51. if _, ok := subitem.(*ast.ObjectType); !ok {
  52. items = append(items, item)
  53. return items, frontier
  54. }
  55. }
  56. // Great! We have a match go through all the items and flatten
  57. for _, elem := range ot.List {
  58. // Add it to the frontier so that we can recurse
  59. frontier = append(frontier, &ast.ObjectItem{
  60. Keys: item.Keys,
  61. Assign: item.Assign,
  62. Val: elem,
  63. LeadComment: item.LeadComment,
  64. LineComment: item.LineComment,
  65. })
  66. }
  67. return items, frontier
  68. }
  69. func flattenObjectType(
  70. ot *ast.ObjectType,
  71. item *ast.ObjectItem,
  72. items []*ast.ObjectItem,
  73. frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
  74. // If the list has no items we do not have to flatten anything
  75. if ot.List.Items == nil {
  76. items = append(items, item)
  77. return items, frontier
  78. }
  79. // All the elements of this object must also be objects!
  80. for _, subitem := range ot.List.Items {
  81. if _, ok := subitem.Val.(*ast.ObjectType); !ok {
  82. items = append(items, item)
  83. return items, frontier
  84. }
  85. }
  86. // Great! We have a match go through all the items and flatten
  87. for _, subitem := range ot.List.Items {
  88. // Copy the new key
  89. keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys))
  90. copy(keys, item.Keys)
  91. copy(keys[len(item.Keys):], subitem.Keys)
  92. // Add it to the frontier so that we can recurse
  93. frontier = append(frontier, &ast.ObjectItem{
  94. Keys: keys,
  95. Assign: item.Assign,
  96. Val: subitem.Val,
  97. LeadComment: item.LeadComment,
  98. LineComment: item.LineComment,
  99. })
  100. }
  101. return items, frontier
  102. }