Commit a3d22ae9 by Ben Tranter

Document logic behind basic diff

parent b54b43a4
...@@ -71,6 +71,8 @@ func NewBasicFormatter(left interface{}) *BasicFormatter { ...@@ -71,6 +71,8 @@ func NewBasicFormatter(left interface{}) *BasicFormatter {
} }
} }
// Format takes the diff of two JSON documents, and returns the difference
// between them summarized in an HTML document.
func (b *BasicFormatter) Format(d diff.Diff) ([]byte, error) { func (b *BasicFormatter) Format(d diff.Diff) ([]byte, error) {
// calling jsonDiff.Format(d) populates the JSON diff's "Lines" value, // calling jsonDiff.Format(d) populates the JSON diff's "Lines" value,
// which we use to compute the basic dif // which we use to compute the basic dif
...@@ -90,23 +92,40 @@ func (b *BasicFormatter) Format(d diff.Diff) ([]byte, error) { ...@@ -90,23 +92,40 @@ func (b *BasicFormatter) Format(d diff.Diff) ([]byte, error) {
return buf.Bytes(), nil return buf.Bytes(), nil
} }
// Basic is V2 of the basic diff // Basic transforms a slice of JSONLines into a slice of BasicBlocks.
func (b *BasicDiff) Basic(lines []*JSONLine) []*BasicBlock { func (b *BasicDiff) Basic(lines []*JSONLine) []*BasicBlock {
// init an array you can append to for the basic "blocks" // init an array you can append to for the basic "blocks"
blocks := make([]*BasicBlock, 0) blocks := make([]*BasicBlock, 0)
// iterate through each line
for _, line := range lines { for _, line := range lines {
// TODO: this condition needs an explaination? what does it mean? // In order to produce distinct "blocks" when rendering the basic diff,
// we need a way to distinguish between differnt sections of data.
// To do this, we consider the value(s) of each top-level JSON key to
// represent a distinct block for Grafana's JSON data structure, so
// we perform this check to see if we've entered a new "block". If we
// have, we simply append the existing block to the array of blocks.
if b.LastIndent == 2 && line.Indent == 1 && line.Change == ChangeNil { if b.LastIndent == 2 && line.Indent == 1 && line.Change == ChangeNil {
if b.Block != nil { if b.Block != nil {
blocks = append(blocks, b.Block) blocks = append(blocks, b.Block)
} }
} }
// Record the last indent level at each pass in case we need to
// check for a change in depth inside the JSON data structures.
b.LastIndent = line.Indent b.LastIndent = line.Indent
// TODO: why special handling for indent 2? // TODO: why special handling for indent 2?
// Here we
// If the line's indentation is at level 1, then we know it's a top
// level key in the JSON document. As mentioned earlier, we treat these
// specially as they indicate their values belong to distinct blocks.
//
// At level 1, we only record single-line changes, ie, the "added",
// "deleted", "old" or "new" cases, since we know those values aren't
// arrays or maps. We only handle these cases at level 2 or deeper,
// since for those we either output a "change" or "summary". This is
// done for formatting reasons only, so we have logical "blocks" to
// display.
if line.Indent == 1 { if line.Indent == 1 {
switch line.Change { switch line.Change {
case ChangeNil: case ChangeNil:
...@@ -139,17 +158,31 @@ func (b *BasicDiff) Basic(lines []*JSONLine) []*BasicBlock { ...@@ -139,17 +158,31 @@ func (b *BasicDiff) Basic(lines []*JSONLine) []*BasicBlock {
b.Block.New = line.Val b.Block.New = line.Val
b.Block.LineEnd = line.LineNum b.Block.LineEnd = line.LineNum
// then write out the change // For every "old" change there is a corresponding "new", which
// is why we wait until we detect the "new" change before
// appending the change.
blocks = append(blocks, b.Block) blocks = append(blocks, b.Block)
default: default:
// ok // ok
} }
} }
// TODO: why special handling for indent > 2 ? // Here is where we handle changes for all types, appending each change
// Other Lines // to the current block based on the value.
//
// Values which only occupy a single line in JSON (like a string or
// int, for example) are treated as "Basic Changes" that we append to
// the current block as soon as they're detected.
//
// Values which occupy multiple lines (either slices or maps) are
// treated as "Basic Summaries". When we detect the "ChangeNil" type,
// we know we've encountered one of these types, so we record the
// starting position as well the type of the change, and stop
// performing comparisons until we find the end of that change. Upon
// finding the change, we append it to the current block, and begin
// performing comparisons again.
if line.Indent > 1 { if line.Indent > 1 {
// Ensure single line change // Ensure a single line change
if line.Key != "" && line.Val != nil && !b.writing { if line.Key != "" && line.Val != nil && !b.writing {
switch line.Change { switch line.Change {
case ChangeAdded, ChangeDeleted: case ChangeAdded, ChangeDeleted:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment