const path = require('path');
const resolve = require('resolve');
const pkgUp = require('pkg-up');
const { resolvePath } = require('babel-plugin-module-resolver');
const { OptionManager } = require('@babel/core');

function getPlugins(file, cwd) {
  try {
    const manager = new OptionManager();
    const result = manager.init({
      babelrc: true,
      filename: file,
      cwd,
    });

    return result.plugins.filter(plugin => plugin.key === 'module-resolver');
  } catch (err) {
    // This error should only occur if something goes wrong with babel's
    // internals. Dump it to console so people know what's going on,
    // elsewise the error will simply be squelched in the calling code.
    console.error('[eslint-import-resolver-babel-module]', err);
    console.error('See: https://github.com/tleunen/eslint-import-resolver-babel-module/pull/34');
    return [];
  }
}

function getPluginOptions(file, cwd, defaultOptions) {
  const instances = getPlugins(file, cwd);

  return instances.reduce(
    (config, plugin) => ({
      cwd: plugin.options.cwd || config.cwd,
      root: config.root.concat(plugin.options.root || []),
      alias: Object.assign(config.alias, plugin.options.alias || {}),
      resolvePath: plugin.options.resolvePath || config.resolvePath,
      extensions: plugin.options.extensions || config.extensions,
    }),
    defaultOptions,
  );
}

function stripWebpack(src, alias) {
  let source = src;
  const aliases = Object.keys(alias);
  let index = source.length;
  aliases.forEach(((element) => {
    const i = source.indexOf(element);
    if (i >= 0 && i < index) {
      index = i;
    }
  }));
  // strip loaders
  const finalBang = index ? source.lastIndexOf('!', index - 1) : -1;
  if (finalBang >= 0) {
    source = source.slice(finalBang + 1);
  }

  // strip resource query
  const finalQuestionMark = source.lastIndexOf('?');
  if (finalQuestionMark >= 0) {
    source = source.slice(0, finalQuestionMark);
  }
  return source;
}

exports.interfaceVersion = 2;

const defaultExtensions = ['.js', '.jsx', '.es', '.es6', '.mjs'];

/**
 * Find the full path to 'source', given 'file' as a full reference path.
 *
 * resolveImport('./foo', '/Users/ben/bar.js') => '/Users/ben/foo.js'
 * @param  {string} source - the module to resolve; i.e './some-module'
 * @param  {string} file - the importing file's full path; i.e. '/usr/local/bin/file.js'
 * @param  {object} options - the resolver options
 * @return {object}
 */
exports.resolve = (source, file, opts) => {
  const options = opts || {};
  if (resolve.isCore(source)) return { found: true, path: null };

  const projectRootDir = path.dirname(pkgUp.sync(file));

  try {
    const pluginOptions = getPluginOptions(
      file,
      projectRootDir,
      {
        // if .babelrc doesn't exist, try to get the configuration information from `options`,
        // which gets defined by the eslint configuration file.
        // e.g. in .eslintrc file
        // "import/resolver": {
        //   "babel-module": {
        //     "root": ["./src"],
        //     "extensions": [".js", ".jsx"]
        //   }
        // }
        cwd: options.cwd || projectRootDir,
        root: options.root || [],
        alias: options.alias || {},
        resolvePath: options.resolvePath,
        extensions: options.extensions || defaultExtensions,
      },
    );

    const finalSource = stripWebpack(source, pluginOptions.alias);
    const resolvePathFunc = pluginOptions.resolvePath || resolvePath;
    const src = resolvePathFunc(finalSource, file, pluginOptions);

    const extensions = options.extensions || pluginOptions.extensions;

    return {
      found: true,
      path: resolve.sync(src || source, {
        ...options,
        extensions,
        basedir: path.dirname(file),
      }),
    };
  } catch (e) {
    return { found: false };
  }
};

@@ -237,16 +237,30 @@
 ile, cwd
+, babelOptions
 ) %7B%0A  tr
@@ -388,24 +388,47 @@
 %0A      cwd,%0A
+      ...babelOptions,%0A
     %7D);%0A%0A   
@@ -1014,16 +1014,45 @@
 ile, cwd
+, defaultOptions.babelOptions
 );%0A%0A  re
@@ -3400,24 +3400,74 @@
 Extensions,%0A
+        babelOptions: options.babelOptions %7C%7C %7B%7D,%0A
       %7D,%0A   

Add support for passing `babelOptions` to `OptionsManager#init` (#113)