This repository has been archived by the owner on Dec 16, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
/
diff.go
104 lines (101 loc) · 2.97 KB
/
diff.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
package vdom
func Diff(t, other *Tree) (PatchSet, error) {
patches := []Patcher{}
if err := recursiveDiff(&patches, t.Children, other.Children); err != nil {
return nil, err
}
return patches, nil
}
func recursiveDiff(patches *[]Patcher, nodes, otherNodes []Node) error {
numOtherNodes := len(otherNodes)
numNodes := len(nodes)
minNumNodes := numOtherNodes
if numOtherNodes > numNodes {
// There are more otherNodes than there are nodes.
// We should append the additional nodes.
for _, otherNode := range otherNodes[numNodes:] {
*patches = append(*patches, &Append{
Parent: otherNode.Parent(),
Child: otherNode,
})
}
minNumNodes = numNodes
} else if numNodes > numOtherNodes {
// There are more nodes than there are otherNodes.
// We should remove the additional children.
for _, node := range nodes[numOtherNodes:] {
*patches = append(*patches, &Remove{
Node: node,
})
}
minNumNodes = numOtherNodes
}
for i := 0; i < minNumNodes; i++ {
otherNode := otherNodes[i]
node := nodes[i]
if match, _ := CompareNodes(node, otherNode, false); !match {
// The nodes have different tag names or values. We should replace
// node with otherNode
*patches = append(*patches, &Replace{
Old: node,
New: otherNode,
})
continue
}
// NOTE: Since CompareNodes checks the type,
// we can only reach here if the nodes are of
// the same type.
if otherEl, ok := otherNode.(*Element); ok {
// Both nodes are elements. We need to treat them differently because
// they have children and attributes.
el := node.(*Element)
// Add the patches needed to make the attributes match (if any)
diffAttributes(patches, el, otherEl)
// Recursively apply diff algorithm to each element's children
recursiveDiff(patches, el.Children(), otherEl.Children())
}
}
return nil
}
// diffAttributes compares the attributes in el to the attributes in otherEl
// and adds the necessary patches to make the attributes in el match those in
// otherEl
func diffAttributes(patches *[]Patcher, el, otherEl *Element) {
otherAttrs := otherEl.AttrMap()
attrs := el.AttrMap()
for attrName := range attrs {
// Remove any attributes in el that are not found in otherEl
if _, found := otherAttrs[attrName]; !found {
*patches = append(*patches, &RemoveAttr{
Node: el,
AttrName: attrName,
})
}
}
// Now iterate through the attributes in otherEl
for name, otherValue := range otherAttrs {
value, found := attrs[name]
if !found {
// The attribute exists in otherEl but not in el,
// we should add it.
*patches = append(*patches, &SetAttr{
Node: el,
Attr: &Attr{
Name: name,
Value: otherValue,
},
})
} else if value != otherValue {
// The attribute exists in el but has a different value
// than it does in otherEl. We should set it to the value
// in otherEl.
*patches = append(*patches, &SetAttr{
Node: el,
Attr: &Attr{
Name: name,
Value: otherValue,
},
})
}
}
}