<commit_before>/**
 * This file has two responsibilities:
 *  Convert a fetched document into an abstract DOM-like structure.
 *  Render a visual representation of the DOM-like structure.
 *
 *  For simplicity sake, I am polluting the global namespace with a drawDOM function, that is used in
 *  the /javascripts/app.js file.
 */

'use strict';


var drawDOM = (function() {

  /**
   * The document host object maintains a live HTMLCollection of certain element tags.
   *
   * While the dom-like structure we are adding won't be live, we can at the very least update the
   * document to contain a quick reference to these nodes using vanilla arrays.
   */
  var docRefTagsMap = {
    HTML: function(newNode, node, documentRef) {
      documentRef.documentElement = newNode;
    },
    HEAD: function(newNode, node, documentRef) {
      documentRef.head = newNode;
    },
    BODY: function(newNode, node, documentRef) {
      documentRef.body = newNode;
    },
    FORM: function (newNode, node, documentRef) {
      documentRef.forms.push(newNode);
    },
    SCRIPT: function(newNode, node, documentRef) {
      documentRef.scripts.push(newNode);
    },
    A: function(newNode, node, documentRef) {
      // conditional if href exists https://developer.mozilla.org/en-US/docs/Web/API/Document/links
      if (node.getAttribute('href')) {
        documentRef.links.push(newNode);
      }
    },
    AREA: function(newNode, node, documentRef) {
      // conditional if href exists https://developer.mozilla.org/en-US/docs/Web/API/Document/links
      if (node.getAttribute('href')) {
        documentRef.links.push(newNode);
      }
    },
    IMG: function(newNode, node, documentRef) {
      documentRef.images.push(newNode);
    }
  };

  var nodeColorMap = {
    HTML: '#000',
    HEAD: '#F00',
    BODY: '#0F0',
    default: '#2F73D8'
  };

  /**
   * Instead of an if-ladder, or checking if an array contains a value, using a map is a convenient and
   * fast way to check if something meets a condition.
   *
   * The following map is similar to ['HTML', 'HEAD', 'BODY'].includes(node.tagName), but rather than
   * traversing the entire array, we get to jump straight to a "true" or "undefined" (which is an implied false).
   */
  var nodesWithVisibleTags = {
    HTML: true,
    HEAD: true,
    BODY: true
  };

  /**
   * These variables are used in drawNodes. Although it seems odd to pull them out of context of that function,
   * drawNodes() gets called for every node in the dom-tree. That means for every node we reinstantiate two
   * variables that don't ever change.
   */
  var startAngle = 0,
    endAngle = 2 * Math.PI;

  /**
   * Traverse down an document, creating a DOM-like structure
   * @param node - the true DOM node
   * @param parentNode - a dom-like representation of our DOM node
   * @param depth - the node's depth, used for the rendering process
   * @param start - the starting range to draw on the canvas
   * @param end - the ending range to draw on the canvas
   * @param documentRef {Object} - An object literal that will get merged into our document-like element after traversal
   *
   * @returns {Object} DOM-like object.
   */
  function traverseDomLikeNode(node, parentNode, depth, start, end, documentRef) {

    if (depth > documentRef.largestDepth) {
      documentRef.largestDepth = depth;
    }

    var newNode = {
      children: [],
      depth: depth,
      end: end,
      start: start,
      tagName: node.tagName,
      parentNode: parentNode
    };

    // If the node has an id, then lets add it directly to the docRef ID map.
    if(node.id) {
      newNode.id = node.id;
      documentRef.ids[node.id] = newNode;
    }

    // If our node is among a set of special cases, lets call a function that updates the documentRef
    if (docRefTagsMap[node.tagName]) {
      docRefTagsMap[node.tagName](newNode, node, documentRef);
    }

    var childDepth = depth + 1,
      childCount = node.childElementCount,
      width = (end - start) / childCount,
      child,
      childStart;

    for (var i = 0; i< node.childElementCount; i++) {

      childStart = start + (i * width);

      child = traverseDomLikeNode(node.children[i], newNode, childDepth, childStart, childStart + width, documentRef);
      newNode.children.push(child);
    }

    return newNode;
  }

  /**
   * Create a DOM-like structure. We will be using vanilla objects as our nodes, and making use of a few<commit_msg>Making node traversal backward compatable<commit_after>/**
 * This file has two responsibilities:
 *  Convert a fetched document into an abstract DOM-like structure.
 *  Render a visual representation of the DOM-like structure.
 *
 *  For simplicity sake, I am polluting the global namespace with a drawDOM function, that is used in
 *  the /javascripts/app.js file.
 */

'use strict';


var drawDOM = (function() {

  /**
   * The document host object maintains a live HTMLCollection of certain element tags.
   *
   * While the dom-like structure we are adding won't be live, we can at the very least update the
   * document to contain a quick reference to these nodes using vanilla arrays.
   */
  var docRefTagsMap = {
    HTML: function(newNode, node, documentRef) {
      documentRef.documentElement = newNode;
    },
    HEAD: function(newNode, node, documentRef) {
      documentRef.head = newNode;
    },
    BODY: function(newNode, node, documentRef) {
      documentRef.body = newNode;
    },
    FORM: function (newNode, node, documentRef) {
      documentRef.forms.push(newNode);
    },
    SCRIPT: function(newNode, node, documentRef) {
      documentRef.scripts.push(newNode);
    },
    A: function(newNode, node, documentRef) {
      // conditional if href exists https://developer.mozilla.org/en-US/docs/Web/API/Document/links
      if (node.attributes.href) {
        documentRef.links.push(newNode);
      }
    },
    AREA: function(newNode, node, documentRef) {
      // conditional if href exists https://developer.mozilla.org/en-US/docs/Web/API/Document/links
      if (node.attributes.href) {
        documentRef.links.push(newNode);
      }
    },
    IMG: function(newNode, node, documentRef) {
      documentRef.images.push(newNode);
    }
  };

  var nodeColorMap = {
    HTML: '#000',
    HEAD: '#F00',
    BODY: '#0F0',
    default: '#2F73D8'
  };

  /**
   * Instead of an if-ladder, or checking if an array contains a value, using a map is a convenient and
   * fast way to check if something meets a condition.
   *
   * The following map is similar to ['HTML', 'HEAD', 'BODY'].includes(node.tagName), but rather than
   * traversing the entire array, we get to jump straight to a "true" or "undefined" (which is an implied false).
   */
  var nodesWithVisibleTags = {
    HTML: true,
    HEAD: true,
    BODY: true
  };

  /**
   * These variables are used in drawNodes. Although it seems odd to pull them out of context of that function,
   * drawNodes() gets called for every node in the dom-tree. That means for every node we reinstantiate two
   * variables that don't ever change.
   */
  var startAngle = 0,
    endAngle = 2 * Math.PI;

  /**
   * Traverse down an document, creating a DOM-like structure
   * @param node - the true DOM node
   * @param parentNode - a dom-like representation of our DOM node
   * @param depth - the node's depth, used for the rendering process
   * @param start - the starting range to draw on the canvas
   * @param end - the ending range to draw on the canvas
   * @param documentRef {Object} - An object literal that will get merged into our document-like element after traversal
   *
   * @returns {Object} DOM-like object.
   */
  function traverseDomLikeNode(node, parentNode, depth, start, end, documentRef) {

    if (depth > documentRef.largestDepth) {
      documentRef.largestDepth = depth;
    }

    var newNode = {
      children: [],
      childElementCount: node.childElementCount,
      attributes: {},
      depth: depth,
      end: end,
      start: start,
      tagName: node.tagName,
      parentNode: parentNode
    };


    var attributes = node.attributes,
      attributesLength,
      attribute;

    /**
     * In the event we are traversing DOM-like nodes (and not real DOM nodes), we can simply set the
     * newNode's attributes object to be the same as the node's attributes.
     *
     * One way we can be sure if we are looking at a REAL DOM element is checking that the attributes instance.
     *
     * (real) Element.attributes returns a NamedNodeMap
     */
    if (attributes instanceof NamedNodeMap) {

      attributesLength = attributes.length || 0;
      for(var i = 0; i < attributesLength; i++) {

        /**
         * If you know that attribute you are setting or getting, you almost always will want to use
         * node.getAttribute(str) or node.setAttribute(). The getter returns the string value of the
         * attribute.
         *
         * Important Note: even if you set an attribute with a number or boolean, it will be returned
         * as a string.
         */
        attribute = attributes[i];
        newNode.attributes[attribute.name] = attribute.value;
      }
    } else {
      newNode.attributes = node.attributes;
    }

    // If the node has an id, then lets add it directly to the docRef ID map.
    if(node.id) {
      newNode.id = node.id;
      documentRef.ids[node.id] = newNode;
    }

    // If our node is among a set of special cases, lets call a function that updates the documentRef
    if (docRefTagsMap[node.tagName]) {
      docRefTagsMap[node.tagName](newNode, node, documentRef);
    }

    var childDepth = depth + 1,
      childCount = node.childElementCount,
      width = (end - start) / childCount,
      child,
      childStart;

    for (var i = 0; i< node.childElementCount; i++) {

      childStart = start + (i * width);

      child = traverseDomLikeNode(node.children[i], newNode, childDepth, childStart, childStart + width, documentRef);
      newNode.children.push(child);
    }

    return newNode;
  }

  /**
   * Create a DOM-like structure. We will be using vanilla objects as our nodes, and making use of a few
{'fraction_non_alphanumeric': 0.09797164237888932, 'fraction_numerical': 0.0031508467900748325, 'mean_word_length': 2.731447465099192, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 5, 'https://': 4, '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': '6117852', 'n_tokens_mistral': 3021, 'n_tokens_neox': 2906, 'n_words': 1073}