<commit_before>
/**
 * Module dependencies.
 */

var Patch = require('./patch');

/**
 * Expose `diff` as the default.
 */

module.exports = exports = diff;

/**
 * Expose `component`
 */

exports.component = diffComponent;

/**
 * Create a patch function from a diff.
 *
 * @param {Node} prev
 * @param {Node} next
 * @api public
 */

function diff(prev, next) {
  var patch = new Patch;
  diffNode(prev, next, patch);
  return function(el){
    return patch.apply(el);
  };
}

/**
 * Create a diff for a single component.
 *
 * @param {Component} component
 * @param {Patch} [patch]
 * @return {Patch}
 * @api public
 */

function diffComponent(component, patch) {
  patch = patch || new Patch;
  var prev = component.node;
  // TODO: Implement shouldUpdate
  component.update();
  var next = component.node;
  diffNode(prev, next, patch);
  return patch;
}

/**
 * Create a diff between two tress of nodes.
 *
 * @param {Node} prev
 * @param {Node} next
 * @param {Patch} [patch]
 * @return {Patch}
 * @api public
 */

function diffNode(prev, next, patch) {
  patch = patch || new Patch;

  // this is a new node.
  if (prev == null) {
    patch.add(next.parent.path(), function(el){
      el.appendChild(next.render());
    });
    return;
  }

  var prevPath = prev.path();

  // the node has been removed.
  if (next == null) {
    patch.add(prevPath, function(el){
      el.parentNode.removeChild(el);
    });
    return;
  }

  // Node type changed
  if (prev.type !== next.type) {
    // removeComponents(prev); // TODO: remove all the components
    patch.add(prevPath, function(el){
      el.parentNode.replaceChild(next.render(), el);
    });
    return;
  }

  // update the text content.
  if (next.isText() && prev.isText()) {
    // TODO: maybe there is a simpler way to represent text?
    // https://github.com/facebook/react/blob/master/src/browser/ReactTextComponent.js#L54
    next.create();
    if (next.instance.data !== prev.instance.data) {
      patch.add(prevPath, function(el){
        el.textContent = next.instance.data;
      });
      return;
    }
  }

  // if they are both components.
  if (next.isComponent() && prev.isComponent()) {
    // they are different components.
    if (next.factory != prev.factory) {
      prev.remove();
      patch.add(prevPath, function(el){
        el.parentNode.replaceChild(next.render(), el);
      });
    } else {
      // they are the same components.
      next.create();
      // transfer the instance over
      // next.instance = prev.instance;
      prev.instance.props = next.instance.props;
      diffComponent(prev.instance, patch);
    }
    return;
  }

  // if they are both elements.
  if (next.isElement() && prev.isElement()) {

    // different node, so swap them.
    if (next.data.tagName !== prev.data.tagName) {
      patch.add(prevPath, function(el){
        el.parentNode.replaceChild(next.render(), el);
      });
      return;
    }

    var nextAttrs = next.data.attributes;
    var prevAttrs = prev.data.attributes;

    // add new props to DOM nodes.
    for (var name in nextAttrs) {
      var value = nextAttrs[name];
      if (!prevAttrs[name] || prevAttrs[name] !== value) {
        patch.add(prevPath, function(el){
          el.setAttribute(name, value);
        });
      }
    }

    // remove old props from DOM nodes.
    for (var name in prevAttrs) {
      if (!nextAttrs[name]) {
        patch.add(prevPath, function(el){
          el.removeAttribute(name);
        });
      }
    }

    // TODO:
    // Order the children using the key attribute in
    // both arrays of children and compare them first, then
    // the other nodes that have been added or removed, then
    // render them in the correct order

    // compare the child nodes.
    zip(prev.children, next.children)
      .forEach(function(item, index){
        diffNode(item[0], item[1], patch);
      });
  }

}

/**
 * Zip multiple arrays together into one array
 *
 * @return {Array}
 */

function zip() {
  var args = Array.prototype.slice.call(arguments, 0);
  return args.reduce(function (a, b) {
    return a.length > b.length ? a : b;
  }, []).map(function (_, i) {<commit_msg>Removed ref to parent node in diff<commit_after>
/**
 * Module dependencies.
 */

var Patch = require('./patch');

/**
 * Expose `diff` as the default.
 */

module.exports = exports = diff;

/**
 * Expose `component`
 */

exports.component = diffComponent;

/**
 * Create a patch function from a diff.
 *
 * @param {Node} prev
 * @param {Node} next
 * @api public
 */

function diff(prev, next) {
  var patch = new Patch;
  diffNode(prev, next, patch);
  return function(el){
    return patch.apply(el);
  };
}

/**
 * Create a diff for a single component.
 *
 * @param {Component} component
 * @param {Patch} [patch]
 * @return {Patch}
 * @api public
 */

function diffComponent(component, patch) {
  patch = patch || new Patch;
  var prev = component.node;
  // TODO: Implement shouldUpdate
  component.update();
  var next = component.node;
  diffNode(prev, next, patch);
  return patch;
}

/**
 * Create a diff between two tress of nodes.
 *
 * @param {Node} prev
 * @param {Node} next
 * @param {Patch} [patch]
 * @return {Patch}
 * @api public
 */

function diffNode(prev, next, patch) {
  patch = patch || new Patch;

  var prevPath = prev.path();

  // the node has been removed.
  if (next == null) {
    patch.add(prevPath, function(el){
      el.parentNode.removeChild(el);
    });
    return;
  }

  // Node type changed
  if (prev.type !== next.type) {
    // removeComponents(prev); // TODO: remove all the components
    patch.add(prevPath, function(el){
      el.parentNode.replaceChild(next.render(), el);
    });
    return;
  }

  // update the text content.
  if (next.isText() && prev.isText()) {
    // TODO: maybe there is a simpler way to represent text?
    // https://github.com/facebook/react/blob/master/src/browser/ReactTextComponent.js#L54
    next.create();
    if (next.instance.data !== prev.instance.data) {
      patch.add(prevPath, function(el){
        el.textContent = next.instance.data;
      });
      return;
    }
  }

  // if they are both components.
  if (next.isComponent() && prev.isComponent()) {
    // they are different components.
    if (next.factory != prev.factory) {
      prev.remove();
      patch.add(prevPath, function(el){
        el.parentNode.replaceChild(next.render(), el);
      });
    } else {
      // they are the same components.
      next.create();
      // transfer the instance over
      // next.instance = prev.instance;
      prev.instance.props = next.instance.props;
      diffComponent(prev.instance, patch);
    }
    return;
  }

  // if they are both elements.
  if (next.isElement() && prev.isElement()) {

    // different node, so swap them.
    if (next.data.tagName !== prev.data.tagName) {
      patch.add(prevPath, function(el){
        el.parentNode.replaceChild(next.render(), el);
      });
      return;
    }

    var nextAttrs = next.data.attributes;
    var prevAttrs = prev.data.attributes;

    // add new props to DOM nodes.
    for (var name in nextAttrs) {
      var value = nextAttrs[name];
      if (!prevAttrs[name] || prevAttrs[name] !== value) {
        patch.add(prevPath, function(el){
          el.setAttribute(name, value);
        });
      }
    }

    // remove old props from DOM nodes.
    for (var name in prevAttrs) {
      if (!nextAttrs[name]) {
        patch.add(prevPath, function(el){
          el.removeAttribute(name);
        });
      }
    }

    // TODO:
    // Order the children using the key attribute in
    // both arrays of children and compare them first, then
    // the other nodes that have been added or removed, then
    // render them in the correct order

    // compare the child nodes.
    var children = zip(prev.children, next.children);

    children.forEach(function(item, index){
      var left = item[0];
      var right = item[1];

      // this is a new node.
      if (left == null) {
        patch.add(next.path(), function(el){
          el.appendChild(right.render());
        });
        return;
      }

      diffNode(left, right, patch);
    });
  }

}

/**
 * Zip multiple arrays together into one array
 *
 * @return {Array}
 */

function zip() {
  var args = Array.prototype.slice.call(arguments, 0);
  return args.reduce(function (a, b) {
    return a.length > b.length ? a : b;
  }, []).map(function (_, i) {
{'fraction_non_alphanumeric': 0.14654661769932473, 'fraction_numerical': 0.0011846937566639024, 'mean_word_length': 2.46694045174538, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4385092', 'n_tokens_mistral': 2654, 'n_tokens_neox': 2625, 'n_words': 734}