Code coverage report for 6to5/traverse/index.js

Statements: 93.44% (57 / 61)      Branches: 91.67% (33 / 36)      Functions: 90% (9 / 10)      Lines: 96% (48 / 50)      Ignored: none     

All files » 6to5/traverse/ » index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 1141 1   1   82124     82123 64 106   64       82059 82059     82056     82056   82056 83291 83291   77220 79214 79214     79204     79200     79186     79001     79001     78990     77220 23915 25909       23904 25933     53305   53291 1             1   1           1 4380     1   1 2   2   2             2     2   2 15 1 1         2    
var VISITOR_KEYS = require("./visitor-keys");
var _            = require("lodash");
 
var traverse = module.exports = function (parent, callbacks, blacklistTypes) {
  // falsy node
  if (!parent) return;
 
  // array of nodes
  if (_.isArray(parent)) {
    _.each(parent, function (node) {
      traverse(node, callbacks, blacklistTypes);
    });
    return;
  }
 
  // unknown node type to traverse
  var keys = VISITOR_KEYS[parent.type];
  if (!keys) return;
 
  // blacklist these node types from being traversed
  blacklistTypes = blacklistTypes || [];
 
  // normalise callbacks
  if (_.isFunction(callbacks)) callbacks = { enter: callbacks };
 
  _.each(keys, function (key) {
    var nodes = parent[key];
    if (!nodes) return;
 
    var handle = function (obj, key) {
      var node = obj[key];
      if (!node) return;
 
      // type is blacklisted
      if (_.contains(blacklistTypes, node.type)) return;
 
      // enter
      var result = callbacks.enter(node, parent, obj, key);
 
      // stop iteration
      if (result === false) return;
 
      // replace node
      if (result != null) node = obj[key] = result;
 
      // traverse node
      traverse(node, callbacks, blacklistTypes);
 
      // exit
      if (callbacks.exit) callbacks.exit(node, parent, obj, key);
    };
 
    if (_.isArray(nodes)) {
      _.each(nodes, function (node, i) {
        handle(nodes, i);
      });
 
      // remove deleted nodes
      parent[key] = _.flatten(parent[key]).filter(function (node) {
        return node !== traverse.Delete;
      });
    } else {
      handle(parent, key);
 
      if (parent[key] === traverse.Delete) {
        throw new Error("trying to delete property " + key + " from " +
                        parent.type + " but can't because it's required");
      }
    }
  });
};
 
traverse.FUNCTION_TYPES = ["ArrowFunctionExpression", "FunctionDeclaration", "FunctionExpression"];
 
traverse.aliases = {
  ArrowFunctionExpression: ["Function"],
  FunctionDeclaration:     ["Function"],
  FunctionExpression:      ["Function"]
};
 
traverse.isFunction = function (node) {
  return _.contains(traverse.FUNCTION_TYPES, node.type);
};
 
traverse.Delete = {};
 
traverse.hasType = function (tree, type, blacklistTypes) {
  blacklistTypes = [].concat(blacklistTypes || []);
 
  var has = false;
 
  Iif (_.isArray(tree)) {
    // array of nodes, find the first
    return !!_.find(tree, function (node) {
      return traverse.hasType(node, type, blacklistTypes);
    });
  } else {
    // the node we're searching in is blacklisted
    Iif (_.contains(blacklistTypes, tree.type)) return false;
 
    // the type we're looking for is the same as the passed node
    Iif (tree.type === type) return true;
 
    traverse(tree, function (node) {
      if (node.type === type) {
        has = true;
        return false;
      }
    }, blacklistTypes);
  }
 
  return has;
};