“use strict”;

Object.defineProperty(exports, “__esModule”, {

value: true

}); exports.runAsync = runAsync; exports.runSync = runSync;

function _traverse() {

const data = _interopRequireDefault(require("@babel/traverse"));

_traverse = function () {
  return data;
};

return data;

}

var _pluginPass = _interopRequireDefault(require(“./plugin-pass”));

var _blockHoistPlugin = _interopRequireDefault(require(“./block-hoist-plugin”));

var _normalizeOpts = _interopRequireDefault(require(“./normalize-opts”));

var _normalizeFile = _interopRequireDefault(require(“./normalize-file”));

var _generate = _interopRequireDefault(require(“./file/generate”));

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

function runAsync(config, code, ast, callback) {

let result;

try {
  result = runSync(config, code, ast);
} catch (err) {
  return callback(err);
}

return callback(null, result);

}

function runSync(config, code, ast) {

const file = (0, _normalizeFile.default)(config.passes, (0, _normalizeOpts.default)(config), code, ast);
const opts = file.opts;

try {
  transformFile(file, config.passes);
} catch (e) {
  var _opts$filename;

  e.message = `${(_opts$filename = opts.filename) !== null && _opts$filename !== void 0 ? _opts$filename : "unknown"}: ${e.message}`;

  if (!e.code) {
    e.code = "BABEL_TRANSFORM_ERROR";
  }

  throw e;
}

let outputCode, outputMap;

try {
  if (opts.code !== false) {
    ({
      outputCode,
      outputMap
    } = (0, _generate.default)(config.passes, file));
  }
} catch (e) {
  var _opts$filename2;

  e.message = `${(_opts$filename2 = opts.filename) !== null && _opts$filename2 !== void 0 ? _opts$filename2 : "unknown"}: ${e.message}`;

  if (!e.code) {
    e.code = "BABEL_GENERATE_ERROR";
  }

  throw e;
}

return {
  metadata: file.metadata,
  options: opts,
  ast: opts.ast === true ? file.ast : null,
  code: outputCode === undefined ? null : outputCode,
  map: outputMap === undefined ? null : outputMap,
  sourceType: file.ast.program.sourceType
};

}

function transformFile(file, pluginPasses) {

for (const pluginPairs of pluginPasses) {
  const passPairs = [];
  const passes = [];
  const visitors = [];

  for (const plugin of pluginPairs.concat([(0, _blockHoistPlugin.default)()])) {
    const pass = new _pluginPass.default(file, plugin.key, plugin.options);
    passPairs.push([plugin, pass]);
    passes.push(pass);
    visitors.push(plugin.visitor);
  }

  for (const [plugin, pass] of passPairs) {
    const fn = plugin.pre;

    if (fn) {
      const result = fn.call(pass, file);

      if (isThenable(result)) {
        throw new Error(`You appear to be using an plugin with an async .pre, ` + `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.`);
      }
    }
  }

  const visitor = _traverse().default.visitors.merge(visitors, passes, file.opts.wrapPluginVisitorMethod);

  (0, _traverse().default)(file.ast, visitor, file.scope);

  for (const [plugin, pass] of passPairs) {
    const fn = plugin.post;

    if (fn) {
      const result = fn.call(pass, file);

      if (isThenable(result)) {
        throw new Error(`You appear to be using an plugin with an async .post, ` + `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.`);
      }
    }
  }
}

}

function isThenable(val) {

return !!val && (typeof val === "object" || typeof val === "function") && !!val.then && typeof val.then === "function";

}