“use strict”;

Object.defineProperty(exports, “__esModule”, {

value: true

}); exports.call = call; exports._call = _call; exports.isBlacklisted = isBlacklisted; exports.visit = visit; exports.skip = skip; exports.skipKey = skipKey; exports.stop = stop; exports.setScope = setScope; exports.setContext = setContext; exports.resync = resync; exports._resyncParent = _resyncParent; exports._resyncKey = _resyncKey; exports._resyncList = _resyncList; exports._resyncRemoved = _resyncRemoved; exports.popContext = popContext; exports.pushContext = pushContext; exports.setup = setup; exports.setKey = setKey; exports.requeue = requeue; exports._getQueueContexts = _getQueueContexts;

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

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

function call(key) {

const opts = this.opts;
this.debug(key);

if (this.node) {
  if (this._call(opts[key])) return true;
}

if (this.node) {
  return this._call(opts[this.node.type] && opts[this.node.type][key]);
}

return false;

}

function _call(fns) {

if (!fns) return false;

for (const fn of fns) {
  if (!fn) continue;
  const node = this.node;
  if (!node) return true;
  const ret = fn.call(this.state, this, this.state);

  if (ret && typeof ret === "object" && typeof ret.then === "function") {
    throw new Error(`You appear to be using a plugin with an async traversal visitor, ` + `which your current version of Babel does not support. ` + `If you're using a published plugin, you may need to upgrade ` + `your @babel/core version.`);
  }

  if (ret) {
    throw new Error(`Unexpected return value from visitor method ${fn}`);
  }

  if (this.node !== node) return true;
  if (this.shouldStop || this.shouldSkip || this.removed) return true;
}

return false;

}

function isBlacklisted() {

const blacklist = this.opts.blacklist;
return blacklist && blacklist.indexOf(this.node.type) > -1;

}

function visit() {

if (!this.node) {
  return false;
}

if (this.isBlacklisted()) {
  return false;
}

if (this.opts.shouldSkip && this.opts.shouldSkip(this)) {
  return false;
}

if (this.call("enter") || this.shouldSkip) {
  this.debug("Skip...");
  return this.shouldStop;
}

this.debug("Recursing into...");

_index.default.node(this.node, this.opts, this.scope, this.state, this, this.skipKeys);

this.call("exit");
return this.shouldStop;

}

function skip() {

this.shouldSkip = true;

}

function skipKey(key) {

this.skipKeys[key] = true;

}

function stop() {

this.shouldStop = true;
this.shouldSkip = true;

}

function setScope() {

if (this.opts && this.opts.noScope) return;
let path = this.parentPath;
let target;

while (path && !target) {
  if (path.opts && path.opts.noScope) return;
  target = path.scope;
  path = path.parentPath;
}

this.scope = this.getScope(target);
if (this.scope) this.scope.init();

}

function setContext(context) {

this.shouldSkip = false;
this.shouldStop = false;
this.removed = false;
this.skipKeys = {};

if (context) {
  this.context = context;
  this.state = context.state;
  this.opts = context.opts;
}

this.setScope();
return this;

}

function resync() {

if (this.removed) return;

this._resyncParent();

this._resyncList();

this._resyncKey();

}

function _resyncParent() {

if (this.parentPath) {
  this.parent = this.parentPath.node;
}

}

function _resyncKey() {

if (!this.container) return;
if (this.node === this.container[this.key]) return;

if (Array.isArray(this.container)) {
  for (let i = 0; i < this.container.length; i++) {
    if (this.container[i] === this.node) {
      return this.setKey(i);
    }
  }
} else {
  for (const key of Object.keys(this.container)) {
    if (this.container[key] === this.node) {
      return this.setKey(key);
    }
  }
}

this.key = null;

}

function _resyncList() {

if (!this.parent || !this.inList) return;
const newContainer = this.parent[this.listKey];
if (this.container === newContainer) return;
this.container = newContainer || null;

}

function _resyncRemoved() {

if (this.key == null || !this.container || this.container[this.key] !== this.node) {
  this._markRemoved();
}

}

function popContext() {

this.contexts.pop();

if (this.contexts.length > 0) {
  this.setContext(this.contexts[this.contexts.length - 1]);
} else {
  this.setContext(undefined);
}

}

function pushContext(context) {

this.contexts.push(context);
this.setContext(context);

}

function setup(parentPath, container, listKey, key) {

this.inList = !!listKey;
this.listKey = listKey;
this.parentKey = listKey || key;
this.container = container;
this.parentPath = parentPath || this.parentPath;
this.setKey(key);

}

function setKey(key) {

this.key = key;
this.node = this.container[this.key];
this.type = this.node && this.node.type;

}

function requeue(pathToQueue = this) {

if (pathToQueue.removed) return;
const contexts = this.contexts;

for (const context of contexts) {
  context.maybeQueue(pathToQueue);
}

}

function _getQueueContexts() {

let path = this;
let contexts = this.contexts;

while (!contexts.length) {
  path = path.parentPath;
  if (!path) break;
  contexts = path.contexts;
}

return contexts;

}