“use strict”;

Object.defineProperty(exports, “__esModule”, {

value: true

}); exports.insertBefore = insertBefore; exports._containerInsert = _containerInsert; exports._containerInsertBefore = _containerInsertBefore; exports._containerInsertAfter = _containerInsertAfter; exports.insertAfter = insertAfter; exports.updateSiblingKeys = updateSiblingKeys; exports._verifyNodeList = _verifyNodeList; exports.unshiftContainer = unshiftContainer; exports.pushContainer = pushContainer; exports.hoist = hoist;

var _cache = require(“../cache”);

var _hoister = _interopRequireDefault(require(“./lib/hoister”));

var _index = _interopRequireDefault(require(“./index”));

var t = _interopRequireWildcard(require(“@babel/types”));

function _getRequireWildcardCache() { if (typeof WeakMap !== “function”) return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; if (obj != null) { var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj = obj; } } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function insertBefore(nodes) {

this._assertUnremoved();

nodes = this._verifyNodeList(nodes);
const {
  parentPath
} = this;

if (parentPath.isExpressionStatement() || parentPath.isLabeledStatement() || parentPath.isExportNamedDeclaration() || parentPath.isExportDefaultDeclaration() && this.isDeclaration()) {
  return parentPath.insertBefore(nodes);
} else if (this.isNodeType("Expression") && !this.isJSXElement() || parentPath.isForStatement() && this.key === "init") {
  if (this.node) nodes.push(this.node);
  return this.replaceExpressionWithStatements(nodes);
} else if (Array.isArray(this.container)) {
  return this._containerInsertBefore(nodes);
} else if (this.isStatementOrBlock()) {
  const shouldInsertCurrentNode = this.node && (!this.isExpressionStatement() || this.node.expression != null);
  this.replaceWith(t.blockStatement(shouldInsertCurrentNode ? [this.node] : []));
  return this.unshiftContainer("body", nodes);
} else {
  throw new Error("We don't know what to do with this node type. " + "We were previously a Statement but we can't fit in here?");
}

}

function _containerInsert(from, nodes) {

this.updateSiblingKeys(from, nodes.length);
const paths = [];
this.container.splice(from, 0, ...nodes);

for (let i = 0; i < nodes.length; i++) {
  const to = from + i;
  const path = this.getSibling(to);
  paths.push(path);

  if (this.context && this.context.queue) {
    path.pushContext(this.context);
  }
}

const contexts = this._getQueueContexts();

for (const path of paths) {
  path.setScope();
  path.debug("Inserted.");

  for (const context of contexts) {
    context.maybeQueue(path, true);
  }
}

return paths;

}

function _containerInsertBefore(nodes) {

return this._containerInsert(this.key, nodes);

}

function _containerInsertAfter(nodes) {

return this._containerInsert(this.key + 1, nodes);

}

function insertAfter(nodes) {

this._assertUnremoved();

nodes = this._verifyNodeList(nodes);
const {
  parentPath
} = this;

if (parentPath.isExpressionStatement() || parentPath.isLabeledStatement() || parentPath.isExportNamedDeclaration() || parentPath.isExportDefaultDeclaration() && this.isDeclaration()) {
  return parentPath.insertAfter(nodes.map(node => {
    return t.isExpression(node) ? t.expressionStatement(node) : node;
  }));
} else if (this.isNodeType("Expression") && !this.isJSXElement() || parentPath.isForStatement() && this.key === "init") {
  if (this.node) {
    let {
      scope
    } = this;

    if (parentPath.isMethod({
      computed: true,
      key: this.node
    })) {
      scope = scope.parent;
    }

    const temp = scope.generateDeclaredUidIdentifier();
    nodes.unshift(t.expressionStatement(t.assignmentExpression("=", t.cloneNode(temp), this.node)));
    nodes.push(t.expressionStatement(t.cloneNode(temp)));
  }

  return this.replaceExpressionWithStatements(nodes);
} else if (Array.isArray(this.container)) {
  return this._containerInsertAfter(nodes);
} else if (this.isStatementOrBlock()) {
  const shouldInsertCurrentNode = this.node && (!this.isExpressionStatement() || this.node.expression != null);
  this.replaceWith(t.blockStatement(shouldInsertCurrentNode ? [this.node] : []));
  return this.pushContainer("body", nodes);
} else {
  throw new Error("We don't know what to do with this node type. " + "We were previously a Statement but we can't fit in here?");
}

}

function updateSiblingKeys(fromIndex, incrementBy) {

if (!this.parent) return;

const paths = _cache.path.get(this.parent);

for (let i = 0; i < paths.length; i++) {
  const path = paths[i];

  if (path.key >= fromIndex) {
    path.key += incrementBy;
  }
}

}

function _verifyNodeList(nodes) {

if (!nodes) {
  return [];
}

if (nodes.constructor !== Array) {
  nodes = [nodes];
}

for (let i = 0; i < nodes.length; i++) {
  const node = nodes[i];
  let msg;

  if (!node) {
    msg = "has falsy node";
  } else if (typeof node !== "object") {
    msg = "contains a non-object node";
  } else if (!node.type) {
    msg = "without a type";
  } else if (node instanceof _index.default) {
    msg = "has a NodePath when it expected a raw object";
  }

  if (msg) {
    const type = Array.isArray(node) ? "array" : typeof node;
    throw new Error(`Node list ${msg} with the index of ${i} and type of ${type}`);
  }
}

return nodes;

}

function unshiftContainer(listKey, nodes) {

this._assertUnremoved();

nodes = this._verifyNodeList(nodes);

const path = _index.default.get({
  parentPath: this,
  parent: this.node,
  container: this.node[listKey],
  listKey,
  key: 0
});

return path._containerInsertBefore(nodes);

}

function pushContainer(listKey, nodes) {

this._assertUnremoved();

nodes = this._verifyNodeList(nodes);
const container = this.node[listKey];

const path = _index.default.get({
  parentPath: this,
  parent: this.node,
  container: container,
  listKey,
  key: container.length
});

return path.replaceWithMultiple(nodes);

}

function hoist(scope = this.scope) {

const hoister = new _hoister.default(this, scope);
return hoister.run();

}