forked from go-yaml/yaml
-
Notifications
You must be signed in to change notification settings - Fork 0
/
origin.go
129 lines (108 loc) · 2.23 KB
/
origin.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package yaml
import "fmt"
const originTag = "origin"
func isScalar(n *Node) bool {
return n.Kind == ScalarNode
}
func addOriginInSeq(n *Node) *Node {
if n.Kind != MappingNode {
return n
}
// in case of a sequence, we use the first element as the key
return addOrigin(n.Content[0], n)
}
func addOriginInMap(key, n *Node) *Node {
if n.Kind != MappingNode {
return n
}
return addOrigin(key, n)
}
func addOrigin(key, n *Node) *Node {
if isOrigin(key) {
return n
}
n.Content = append(n.Content, getNamedMap(originTag, append(getKeyLocation(key), getNamedMap("fields", getFieldLocations(n))...))...)
return n
}
func getFieldLocations(n *Node) []*Node {
l := len(n.Content)
size := 0
for i := 0; i < l; i += 2 {
if isScalar(n.Content[i+1]) {
size += 2
}
}
nodes := make([]*Node, 0, size)
for i := 0; i < l; i += 2 {
if isScalar(n.Content[i+1]) {
nodes = append(nodes, getNodeLocation(n.Content[i])...)
}
}
return nodes
}
// isOrigin returns true if the key is an "origin" element
// the current implementation is not optimal, as it relies on the key's line number
// a better design would be to use a dedicated field in the Node struct
func isOrigin(key *Node) bool {
return key.Line == 0
}
func getNodeLocation(n *Node) []*Node {
return getNamedMap(n.Value, getLocationObject(n))
}
func getKeyLocation(n *Node) []*Node {
return getNamedMap("key", getLocationObject(n))
}
func getNamedMap(title string, content []*Node) []*Node {
if len(content) == 0 {
return nil
}
return []*Node{
{
Kind: ScalarNode,
Tag: "!!str",
Value: title,
},
getMap(content),
}
}
func getMap(content []*Node) *Node {
return &Node{
Kind: MappingNode,
Tag: "!!map",
Content: content,
}
}
func getLocationObject(key *Node) []*Node {
return []*Node{
{
Kind: ScalarNode,
Tag: "!!str",
Value: "line",
},
{
Kind: ScalarNode,
Tag: "!!int",
Value: fmt.Sprintf("%d", key.Line),
},
{
Kind: ScalarNode,
Tag: "!!str",
Value: "column",
},
{
Kind: ScalarNode,
Tag: "!!int",
Value: fmt.Sprintf("%d", key.Column),
},
{
Kind: ScalarNode,
Tag: "!!str",
Value: "name",
},
{
Kind: ScalarNode,
Tag: "!!string",
Value: key.Value,
},
}
}