From a3d22ae9c7e35cc332cfc02353f6b8595cf1869b Mon Sep 17 00:00:00 2001 From: Ben Tranter Date: Thu, 22 Jun 2017 18:23:31 -0400 Subject: [PATCH] Document logic behind basic diff --- pkg/components/dashdiffs/formatter_basic.go | 47 ++++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/pkg/components/dashdiffs/formatter_basic.go b/pkg/components/dashdiffs/formatter_basic.go index 01c7757112d..5b1d5504bc6 100644 --- a/pkg/components/dashdiffs/formatter_basic.go +++ b/pkg/components/dashdiffs/formatter_basic.go @@ -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) { // calling jsonDiff.Format(d) populates the JSON diff's "Lines" value, // which we use to compute the basic dif @@ -90,23 +92,40 @@ func (b *BasicFormatter) Format(d diff.Diff) ([]byte, error) { 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 { // init an array you can append to for the basic "blocks" blocks := make([]*BasicBlock, 0) - // iterate through each line 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.Block != nil { 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 // 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 { switch line.Change { case ChangeNil: @@ -139,17 +158,31 @@ func (b *BasicDiff) Basic(lines []*JSONLine) []*BasicBlock { b.Block.New = line.Val 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) default: // ok } } - // TODO: why special handling for indent > 2 ? - // Other Lines + // Here is where we handle changes for all types, appending each change + // 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 { - // Ensure single line change + // Ensure a single line change if line.Key != "" && line.Val != nil && !b.writing { switch line.Change { case ChangeAdded, ChangeDeleted: