src/debug/diff_dom_and_vdom.js
function recursiveDiff(vtree, elem) {
  var output = '';
  if (vtree == null && elem != null) {
    // If the VTree ran out but DOM still exists
    output += '<ins>' + utils.elementToString(elem, chars) + '</ins>';
  } else if (isVNode(vtree)) {
    if (!elem || elem.nodeType !== utils.NODE_TYPES.ELEMENT) {
      // If vtree is a VNode, but elem isn't an Element
      output += '<del>' + vNodeToString(vtree, true, false) + '</del>';
      if (elem) {
        output += '<ins>' + utils.elementToString(elem, chars) + '</ins>';
      }
    } else {
      // Diff elements and recurse
      output += diffElements(vtree, elem);
    }
  } else if (isVText(vtree)) {
    if (!elem || elem.nodeType !== utils.NODE_TYPES.TEXT) {
      // If vtree is a VText, but elem isn't a textNode
      output += '<del>' + escapeString(vtree.text) + '</del>';
      if (elem) {
        output += '<ins>' + utils.elementToString(elem, chars) + '</ins>';
      }
    } else {
      output += textDiff(vtree.text, elem.textContent);
    }
  } else if (isWidget(vtree)) {
    var widgetName;
    // Widgets are the construct that hold childViews
    if (vtree.constructor === HTMLCommentWidget) {
      // HTMLCommentWidget is a special case
      if (!elem || elem.nodeType !== utils.NODE_TYPES.COMMENT) {
        output += '<del>' + utils.getCommentString(escapeString(vtree.text), chars) + '</del>';
        if (elem) {
          output += '<ins>' + utils.elementToString(elem, chars) + '</ins>';
        }
      } else {
        output += utils.getCommentString(textDiff(escapeString(vtree.text), elem.textContent), chars);
      }
    } else if (vtree && vtree.view) {
      widgetName = vtree.view.getDebugName();
      if (typeof vtree.templateToString === 'function') {
        widgetName = vtree.templateToString(recursiveDiff);
      }
      if (vtree.view.el !== elem) {
        // If the view at this position isn't bound to elem, something has gone terribly wrong
        output += '<del><ins>' + widgetName + '</ins></del>';
      } else {
        output += widgetName;
      }
    } else if (vtree && typeof vtree.diff === 'function') {
      output += vtree.diff(elem, recursiveDiff);
    } else {
      output += '<del>[Uninitialized child view]</del>';
      output += '<ins>' + utils.elementToString(elem, chars) + '</ins>';
    }
  }
  return output;
}
function recursiveDiff(vtree, elem) {
  var output = '';
  if (vtree == null && elem != null) {
    // If the VTree ran out but DOM still exists
    output += '<ins>' + utils.elementToString(elem, chars) + '</ins>';
  } else if (isVNode(vtree)) {
    if (!elem || elem.nodeType !== utils.NODE_TYPES.ELEMENT) {
      // If vtree is a VNode, but elem isn't an Element
      output += '<del>' + vNodeToString(vtree, true, false) + '</del>';
      if (elem) {
        output += '<ins>' + utils.elementToString(elem, chars) + '</ins>';
      }
    } else {
      // Diff elements and recurse
      output += diffElements(vtree, elem);
    }
  } else if (isVText(vtree)) {
    if (!elem || elem.nodeType !== utils.NODE_TYPES.TEXT) {
      // If vtree is a VText, but elem isn't a textNode
      output += '<del>' + escapeString(vtree.text) + '</del>';
      if (elem) {
        output += '<ins>' + utils.elementToString(elem, chars) + '</ins>';
      }
    } else {
      output += textDiff(vtree.text, elem.textContent);
    }
  } else if (isWidget(vtree)) {
    var widgetName;
    // Widgets are the construct that hold childViews
    if (vtree.constructor === HTMLCommentWidget) {
      // HTMLCommentWidget is a special case
      if (!elem || elem.nodeType !== utils.NODE_TYPES.COMMENT) {
        output += '<del>' + utils.getCommentString(escapeString(vtree.text), chars) + '</del>';
        if (elem) {
          output += '<ins>' + utils.elementToString(elem, chars) + '</ins>';
        }
      } else {
        output += utils.getCommentString(textDiff(escapeString(vtree.text), elem.textContent), chars);
      }
    } else if (vtree && vtree.view) {
      widgetName = vtree.view.getDebugName();
      if (typeof vtree.templateToString === 'function') {
        widgetName = vtree.templateToString(recursiveDiff);
      }
      if (vtree.view.el !== elem) {
        // If the view at this position isn't bound to elem, something has gone terribly wrong
        output += '<del><ins>' + widgetName + '</ins></del>';
      } else {
        output += widgetName;
      }
    } else if (vtree && typeof vtree.diff === 'function') {
      output += vtree.diff(elem, recursiveDiff);
    } else {
      output += '<del>[Uninitialized child view]</del>';
      output += '<ins>' + utils.elementToString(elem, chars) + '</ins>';
    }
  }
  return output;
}
function recursiveDiff ( vtree , elem ) { var output = '' ; if ( vtree == null && elem != null ) { // If the VTree ran out but DOM still exists output += '<ins>' + utils . elementToString ( elem , chars ) + '</ins>' ; } else if ( isVNode ( vtree ) ) { if ( ! elem || elem . nodeType !== utils . NODE_TYPES . ELEMENT ) { // If vtree is a VNode, but elem isn't an Element output += '<del>' + vNodeToString ( vtree , true , false ) + '</del>' ; if ( elem ) { output += '<ins>' + utils . elementToString ( elem , chars ) + '</ins>' ; } } else { // Diff elements and recurse output += diffElements ( vtree , elem ) ; } } else if ( isVText ( vtree ) ) { if ( ! elem || elem . nodeType !== utils . NODE_TYPES . TEXT ) { // If vtree is a VText, but elem isn't a textNode output += '<del>' + escapeString ( vtree . text ) + '</del>' ; if ( elem ) { output += '<ins>' + utils . elementToString ( elem , chars ) + '</ins>' ; } } else { output += textDiff ( vtree . text , elem . textContent ) ; } } else if ( isWidget ( vtree ) ) { var widgetName ; // Widgets are the construct that hold childViews if ( vtree . constructor === HTMLCommentWidget ) { // HTMLCommentWidget is a special case if ( ! elem || elem . nodeType !== utils . NODE_TYPES . COMMENT ) { output += '<del>' + utils . getCommentString ( escapeString ( vtree . text ) , chars ) + '</del>' ; if ( elem ) { output += '<ins>' + utils . elementToString ( elem , chars ) + '</ins>' ; } } else { output += utils . getCommentString ( textDiff ( escapeString ( vtree . text ) , elem . textContent ) , chars ) ; } } else if ( vtree && vtree . view ) { widgetName = vtree . view . getDebugName ( ) ; if ( typeof vtree . templateToString === 'function' ) { widgetName = vtree . templateToString ( recursiveDiff ) ; } if ( vtree . view . el !== elem ) { // If the view at this position isn't bound to elem, something has gone terribly wrong output += '<del><ins>' + widgetName + '</ins></del>' ; } else { output += widgetName ; } } else if ( vtree && typeof vtree . diff === 'function' ) { output += vtree . diff ( elem , recursiveDiff ) ; } else { output += '<del>[Uninitialized child view]</del>' ; output += '<ins>' + utils . elementToString ( elem , chars ) + '</ins>' ; } } return output ; }
Iterates over a VirtualDOM and DOM structure to create a diff string

@param  {Object}  vtree VirtualDOM object
@param  {Element} elem  DOM object

@return {string}        Diff string
Iterates over a VirtualDOM and DOM structure to create a diff string