-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdiff.go
106 lines (95 loc) · 2.37 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
105
106
// Tideland Go Dynamic JSON
//
// Copyright (C) 2019-2023 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.
package dynaj // import "tideland.dev/go/dynaj"
//--------------------
// DIFFERENCE
//--------------------
// Diff manages the two parsed documents and their differences.
type Diff struct {
first *Document
second *Document
paths []string
}
// Compare parses and compares the documents and returns their differences.
func Compare(first, second []byte) (*Diff, error) {
fd, err := Unmarshal(first)
if err != nil {
return nil, err
}
sd, err := Unmarshal(second)
if err != nil {
return nil, err
}
d := &Diff{
first: fd,
second: sd,
}
err = d.compare()
if err != nil {
return nil, err
}
return d, nil
}
// CompareDocuments compares the documents and returns their differences.
func CompareDocuments(first, second *Document) (*Diff, error) {
d := &Diff{
first: first,
second: second,
}
err := d.compare()
if err != nil {
return nil, err
}
return d, nil
}
// FirstDocument returns the first document passed to Diff().
func (d *Diff) FirstDocument() *Document {
return d.first
}
// SecondDocument returns the second document passed to Diff().
func (d *Diff) SecondDocument() *Document {
return d.second
}
// Differences returns a list of paths where the documents
// have different content.
func (d *Diff) Differences() []string {
return d.paths
}
// DifferenceAt returns the differences at the given path by
// returning the first and the second value.
func (d *Diff) DifferenceAt(path string) (*Node, *Node) {
fstNode := d.first.NodeAt(path)
sndNode := d.second.NodeAt(path)
return fstNode, sndNode
}
// compare iterates over the both documents looking for different
// values or even paths.
func (d *Diff) compare() error {
firstPaths := map[string]struct{}{}
firstProcessor := func(node *Node) error {
firstPaths[node.path] = struct{}{}
if !node.Equals(d.second.NodeAt(node.path)) {
d.paths = append(d.paths, node.path)
}
return nil
}
err := d.first.Root().Process(firstProcessor)
if err != nil {
return err
}
secondProcessor := func(node *Node) error {
_, ok := firstPaths[node.path]
if ok {
// Been there, done that.
return nil
}
d.paths = append(d.paths, node.path)
return nil
}
return d.second.Root().Process(secondProcessor)
}
// EOF