<commit_before>// TODO: Clean up

var t = require("../../types");

var buildVariableAssign = function (opts, id, init) {
  var op = opts.operator;
  if (t.isMemberExpression(id)) op = "=";

  if (op) {
    return t.expressionStatement(t.assignmentExpression("=", id, init));
  } else {
    return t.variableDeclaration(opts.kind, [
      t.variableDeclarator(id, init)
    ]);
  }
};

var push = function (opts, nodes, elem, parentId) {
  if (t.isObjectPattern(elem)) {
    pushObjectPattern(opts, nodes, elem, parentId);
  } else if (t.isArrayPattern(elem)) {
    pushArrayPattern(opts, nodes, elem, parentId);
  } else if (t.isAssignmentPattern(elem)) {
    return;
  } else {
    nodes.push(buildVariableAssign(opts, elem, parentId));
  }
};

var pushObjectPattern = function (opts, nodes, pattern, parentId) {
  for (var i in pattern.properties) {
    var prop = pattern.properties[i];
    if (t.isSpreadProperty(prop)) {
        // get all the keys that appear in this object before the current spread
        var keys = [];
        for (var i2 in pattern.properties) {
          var prop2 = pattern.properties[i2];

          if (i2 >= i) break;
          if (t.isSpreadProperty(prop2)) continue;

          var key = prop2.key;
          if (t.isIdentifier(key)) {
            key = t.literal(prop2.key.name);
          }
          keys.push(key);
        }
        keys = t.arrayExpression(keys);

        var value = t.callExpression(opts.file.addHelper("object-without-properties"), [parentId, keys]);
        nodes.push(buildVariableAssign(opts, prop.argument, value));
    } else {
      if (t.isLiteral(prop.key)) prop.computed = true;

      var pattern2   = prop.value;
      var patternId2 = t.memberExpression(parentId, prop.key, prop.computed);

      if (t.isPattern(pattern2)) {
        push(opts, nodes, pattern2, patternId2);
      } else {
        nodes.push(buildVariableAssign(opts, pattern2, patternId2));
      }
    }
  }
};

var pushArrayPattern = function (opts, nodes, pattern, parentId) {
  if (!pattern.elements) return;

  var i;

  var hasSpreadElement = false;
  for (i in pattern.elements) {
    if (t.isSpreadElement(pattern.elements[i])) {
      hasSpreadElement = true;
      break;
    }
  }

  var toArray = opts.file.toArray(parentId, !hasSpreadElement && pattern.elements.length);

  var _parentId = opts.scope.generateUidBasedOnNode(parentId, opts.file);
  nodes.push(t.variableDeclaration("var", [
    t.variableDeclarator(_parentId, toArray)
  ]));
  parentId = _parentId;

  for (i in pattern.elements) {
    var elem = pattern.elements[i];
    if (!elem) continue;

    i = +i;

    var newPatternId;

    if (t.isSpreadElement(elem)) {
      newPatternId = opts.file.toArray(parentId);

      if (i > 0) {
        newPatternId = t.callExpression(t.memberExpression(newPatternId, t.identifier("slice")), [t.literal(i)]);
      }

      elem = elem.argument;
    } else {
      newPatternId = t.memberExpression(parentId, t.literal(i), true);
    }

    push(opts, nodes, elem, newPatternId);
  }
};

var pushPattern = function (opts) {
  var nodes = opts.nodes;
  var pattern = opts.pattern;
  var parentId = opts.id;
  var file = opts.file;
  var scope = opts.scope;

  if (!t.isMemberExpression(parentId) && !t.isIdentifier(parentId)) {
    var key = scope.generateUidBasedOnNode(parentId, file);

    nodes.push(t.variableDeclaration("var", [
      t.variableDeclarator(key, parentId)
    ]));

    parentId = key;
  }

  push(opts, nodes, pattern, parentId);
};

exports.ForInStatement =
exports.ForOfStatement = function (node, parent, file, scope) {
  var declar = node.left;
  if (!t.isVariableDeclaration(declar)) return;

  var pattern = declar.declarations[0].id;
  if (!t.isPattern(pattern)) return;

  var key = file.generateUidIdentifier("ref", scope);
  node.left = t.variableDeclaration(declar.kind, [
    t.variableDeclarator(key, null)
  ]);

  var nodes = [];

  push({
    kind: declar.kind,
    file: file,
    scope: scope
  }, nodes, pattern, key);

  t.ensureBlock(node);

  var block = node.body;
  block.body = nodes.concat(block.body);
};

exports.Function = function (node, parent, file, scope) {
  var nodes = [];

  var hasDestructuring = false;

  node.params = node.params.map(function (pattern) {
    if (!t.isPattern(pattern)) return pattern;

    hasDestructuring = true;
    var parentId = file.generateUidIdentifier("ref", scope);

    pushPattern({
      kind:    "var",
      nodes:   nodes,
      pattern: pattern,
      id:      parentId,
      file:    file,
      scope:   scope
    });

    return parentId;
  });

  if (!hasDestructuring) return;

  t.ensureBlock(node);

  var block = node.body;
  block.body = nodes.concat(block.body);<commit_msg>add destructuring defaults #230<commit_after>// TODO: Clean up

var t = require("../../types");

var buildVariableAssign = function (opts, id, init) {
  var op = opts.operator;
  if (t.isMemberExpression(id)) op = "=";

  if (op) {
    return t.expressionStatement(t.assignmentExpression("=", id, init));
  } else {
    return t.variableDeclaration(opts.kind, [
      t.variableDeclarator(id, init)
    ]);
  }
};

var push = function (opts, nodes, elem, parentId) {
  if (t.isObjectPattern(elem)) {
    pushObjectPattern(opts, nodes, elem, parentId);
  } else if (t.isArrayPattern(elem)) {
    pushArrayPattern(opts, nodes, elem, parentId);
  } else if (t.isAssignmentPattern(elem)) {
    pushAssignmentPattern(opts, nodes, elem, parentId);
  } else {
    nodes.push(buildVariableAssign(opts, elem, parentId));
  }
};

var pushAssignmentPattern = function (opts, nodes, pattern, parentId) {
  var tempParentId = opts.scope.generateUidBasedOnNode(parentId, opts.file);

  nodes.push(t.variableDeclaration("var", [
    t.variableDeclarator(tempParentId, parentId)
  ]));

  nodes.push(buildVariableAssign(
    opts,
    pattern.left,
    t.conditionalExpression(
      t.binaryExpression("===", tempParentId, t.identifier("undefined")),
      pattern.right,
      tempParentId
    )
  ));
};

var pushObjectPattern = function (opts, nodes, pattern, parentId) {
  for (var i in pattern.properties) {
    var prop = pattern.properties[i];
    if (t.isSpreadProperty(prop)) {
        // get all the keys that appear in this object before the current spread
        var keys = [];
        for (var i2 in pattern.properties) {
          var prop2 = pattern.properties[i2];

          if (i2 >= i) break;
          if (t.isSpreadProperty(prop2)) continue;

          var key = prop2.key;
          if (t.isIdentifier(key)) {
            key = t.literal(prop2.key.name);
          }
          keys.push(key);
        }
        keys = t.arrayExpression(keys);

        var value = t.callExpression(opts.file.addHelper("object-without-properties"), [parentId, keys]);
        nodes.push(buildVariableAssign(opts, prop.argument, value));
    } else {
      if (t.isLiteral(prop.key)) prop.computed = true;

      var pattern2   = prop.value;
      var patternId2 = t.memberExpression(parentId, prop.key, prop.computed);

      if (t.isPattern(pattern2)) {
        push(opts, nodes, pattern2, patternId2);
      } else {
        nodes.push(buildVariableAssign(opts, pattern2, patternId2));
      }
    }
  }
};

var pushArrayPattern = function (opts, nodes, pattern, parentId) {
  if (!pattern.elements) return;

  var i;

  var hasSpreadElement = false;
  for (i in pattern.elements) {
    if (t.isSpreadElement(pattern.elements[i])) {
      hasSpreadElement = true;
      break;
    }
  }

  var toArray = opts.file.toArray(parentId, !hasSpreadElement && pattern.elements.length);

  var _parentId = opts.scope.generateUidBasedOnNode(parentId, opts.file);
  nodes.push(t.variableDeclaration("var", [
    t.variableDeclarator(_parentId, toArray)
  ]));
  parentId = _parentId;

  for (i in pattern.elements) {
    var elem = pattern.elements[i];
    if (!elem) continue;

    i = +i;

    var newPatternId;

    if (t.isSpreadElement(elem)) {
      newPatternId = opts.file.toArray(parentId);

      if (i > 0) {
        newPatternId = t.callExpression(t.memberExpression(newPatternId, t.identifier("slice")), [t.literal(i)]);
      }

      elem = elem.argument;
    } else {
      newPatternId = t.memberExpression(parentId, t.literal(i), true);
    }

    push(opts, nodes, elem, newPatternId);
  }
};

var pushPattern = function (opts) {
  var nodes = opts.nodes;
  var pattern = opts.pattern;
  var parentId = opts.id;
  var file = opts.file;
  var scope = opts.scope;

  if (!t.isMemberExpression(parentId) && !t.isIdentifier(parentId)) {
    var key = scope.generateUidBasedOnNode(parentId, file);

    nodes.push(t.variableDeclaration("var", [
      t.variableDeclarator(key, parentId)
    ]));

    parentId = key;
  }

  push(opts, nodes, pattern, parentId);
};

exports.ForInStatement =
exports.ForOfStatement = function (node, parent, file, scope) {
  var declar = node.left;
  if (!t.isVariableDeclaration(declar)) return;

  var pattern = declar.declarations[0].id;
  if (!t.isPattern(pattern)) return;

  var key = file.generateUidIdentifier("ref", scope);
  node.left = t.variableDeclaration(declar.kind, [
    t.variableDeclarator(key, null)
  ]);

  var nodes = [];

  push({
    kind: declar.kind,
    file: file,
    scope: scope
  }, nodes, pattern, key);

  t.ensureBlock(node);

  var block = node.body;
  block.body = nodes.concat(block.body);
};

exports.Function = function (node, parent, file, scope) {
  var nodes = [];

  var hasDestructuring = false;

  node.params = node.params.map(function (pattern) {
    if (!t.isPattern(pattern)) return pattern;

    hasDestructuring = true;
    var parentId = file.generateUidIdentifier("ref", scope);

    pushPattern({
      kind:    "var",
      nodes:   nodes,
      pattern: pattern,
      id:      parentId,
      file:    file,
      scope:   scope
    });

    return parentId;
  });

  if (!hasDestructuring) return;

  t.ensureBlock(node);

  var block = node.body;
  block.body = nodes.concat(block.body);
};

exports.CatchClause = function (node, parent, file, scope) {
  var pattern = node.param;
  if (!t.isPattern(pattern)) return;

  var ref = file.generateUidIdentifier("ref", scope);
  node.param = ref;

  var nodes = [];

  push({
    kind: "var",
    file: file,
    scope: scope
  }, nodes, pattern, ref);

  node.body.body = nodes.concat(node.body.body);
{'fraction_non_alphanumeric': 0.1387416899508623, 'fraction_numerical': 0.003372193852972348, 'mean_word_length': 3.0515222482435598, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, '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': '253658', 'n_tokens_mistral': 3409, 'n_tokens_neox': 3339, 'n_words': 756}