“use strict”;

Object.defineProperty(exports, “__esModule”, {

value: true

}); exports.buildPresetChain = buildPresetChain; exports.buildRootChain = buildRootChain; exports.buildPresetChainWalker = void 0;

function _path() {

const data = _interopRequireDefault(require("path"));

_path = function () {
  return data;
};

return data;

}

function _debug() {

const data = _interopRequireDefault(require("debug"));

_debug = function () {
  return data;
};

return data;

}

var _options = require(“./validation/options”);

var _patternToRegex = _interopRequireDefault(require(“./pattern-to-regex”));

var _files = require(“./files”);

var _caching = require(“./caching”);

var _configDescriptors = require(“./config-descriptors”);

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

const debug = (0, _debug().default)(“babel:config:config-chain”);

function buildPresetChain(arg, context) {

const chain = buildPresetChainWalker(arg, context);
if (!chain) return null;
return {
  plugins: dedupDescriptors(chain.plugins),
  presets: dedupDescriptors(chain.presets),
  options: chain.options.map(o => normalizeOptions(o))
};

}

const buildPresetChainWalker = makeChainWalker({

init: arg => arg,
root: preset => loadPresetDescriptors(preset),
env: (preset, envName) => loadPresetEnvDescriptors(preset)(envName),
overrides: (preset, index) => loadPresetOverridesDescriptors(preset)(index),
overridesEnv: (preset, index, envName) => loadPresetOverridesEnvDescriptors(preset)(index)(envName)

}); exports.buildPresetChainWalker = buildPresetChainWalker; const loadPresetDescriptors = (0, _caching.makeWeakCache)(preset => buildRootDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors)); const loadPresetEnvDescriptors = (0, _caching.makeWeakCache)(preset => (0, _caching.makeStrongCache)(envName => buildEnvDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors, envName))); const loadPresetOverridesDescriptors = (0, _caching.makeWeakCache)(preset => (0, _caching.makeStrongCache)(index => buildOverrideDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors, index))); const loadPresetOverridesEnvDescriptors = (0, _caching.makeWeakCache)(preset => (0, _caching.makeStrongCache)(index => (0, _caching.makeStrongCache)(envName => buildOverrideEnvDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors, index, envName))));

function buildRootChain(opts, context) {

const programmaticChain = loadProgrammaticChain({
  options: opts,
  dirname: context.cwd
}, context);
if (!programmaticChain) return null;
let configFile;

if (typeof opts.configFile === "string") {
  configFile = (0, _files.loadConfig)(opts.configFile, context.cwd, context.envName, context.caller);
} else if (opts.configFile !== false) {
  configFile = (0, _files.findRootConfig)(context.root, context.envName, context.caller);
}

let {
  babelrc,
  babelrcRoots
} = opts;
let babelrcRootsDirectory = context.cwd;
const configFileChain = emptyChain();

if (configFile) {
  const validatedFile = validateConfigFile(configFile);
  const result = loadFileChain(validatedFile, context);
  if (!result) return null;

  if (babelrc === undefined) {
    babelrc = validatedFile.options.babelrc;
  }

  if (babelrcRoots === undefined) {
    babelrcRootsDirectory = validatedFile.dirname;
    babelrcRoots = validatedFile.options.babelrcRoots;
  }

  mergeChain(configFileChain, result);
}

const pkgData = typeof context.filename === "string" ? (0, _files.findPackageData)(context.filename) : null;
let ignoreFile, babelrcFile;
const fileChain = emptyChain();

if ((babelrc === true || babelrc === undefined) && pkgData && babelrcLoadEnabled(context, pkgData, babelrcRoots, babelrcRootsDirectory)) {
  ({
    ignore: ignoreFile,
    config: babelrcFile
  } = (0, _files.findRelativeConfig)(pkgData, context.envName, context.caller));

  if (ignoreFile && shouldIgnore(context, ignoreFile.ignore, null, ignoreFile.dirname)) {
    return null;
  }

  if (babelrcFile) {
    const result = loadFileChain(validateBabelrcFile(babelrcFile), context);
    if (!result) return null;
    mergeChain(fileChain, result);
  }
}

const chain = mergeChain(mergeChain(mergeChain(emptyChain(), configFileChain), fileChain), programmaticChain);
return {
  plugins: dedupDescriptors(chain.plugins),
  presets: dedupDescriptors(chain.presets),
  options: chain.options.map(o => normalizeOptions(o)),
  ignore: ignoreFile || undefined,
  babelrc: babelrcFile || undefined,
  config: configFile || undefined
};

}

function babelrcLoadEnabled(context, pkgData, babelrcRoots, babelrcRootsDirectory) {

if (typeof babelrcRoots === "boolean") return babelrcRoots;
const absoluteRoot = context.root;

if (babelrcRoots === undefined) {
  return pkgData.directories.indexOf(absoluteRoot) !== -1;
}

let babelrcPatterns = babelrcRoots;
if (!Array.isArray(babelrcPatterns)) babelrcPatterns = [babelrcPatterns];
babelrcPatterns = babelrcPatterns.map(pat => {
  return typeof pat === "string" ? _path().default.resolve(babelrcRootsDirectory, pat) : pat;
});

if (babelrcPatterns.length === 1 && babelrcPatterns[0] === absoluteRoot) {
  return pkgData.directories.indexOf(absoluteRoot) !== -1;
}

return babelrcPatterns.some(pat => {
  if (typeof pat === "string") {
    pat = (0, _patternToRegex.default)(pat, babelrcRootsDirectory);
  }

  return pkgData.directories.some(directory => {
    return matchPattern(pat, babelrcRootsDirectory, directory, context);
  });
});

}

const validateConfigFile = (0, _caching.makeWeakCache)(file => ({

filepath: file.filepath,
dirname: file.dirname,
options: (0, _options.validate)("configfile", file.options)

})); const validateBabelrcFile = (0, _caching.makeWeakCache)(file => ({

filepath: file.filepath,
dirname: file.dirname,
options: (0, _options.validate)("babelrcfile", file.options)

})); const validateExtendFile = (0, _caching.makeWeakCache)(file => ({

filepath: file.filepath,
dirname: file.dirname,
options: (0, _options.validate)("extendsfile", file.options)

})); const loadProgrammaticChain = makeChainWalker({

root: input => buildRootDescriptors(input, "base", _configDescriptors.createCachedDescriptors),
env: (input, envName) => buildEnvDescriptors(input, "base", _configDescriptors.createCachedDescriptors, envName),
overrides: (input, index) => buildOverrideDescriptors(input, "base", _configDescriptors.createCachedDescriptors, index),
overridesEnv: (input, index, envName) => buildOverrideEnvDescriptors(input, "base", _configDescriptors.createCachedDescriptors, index, envName)

}); const loadFileChain = makeChainWalker({

root: file => loadFileDescriptors(file),
env: (file, envName) => loadFileEnvDescriptors(file)(envName),
overrides: (file, index) => loadFileOverridesDescriptors(file)(index),
overridesEnv: (file, index, envName) => loadFileOverridesEnvDescriptors(file)(index)(envName)

}); const loadFileDescriptors = (0, _caching.makeWeakCache)(file => buildRootDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors)); const loadFileEnvDescriptors = (0, _caching.makeWeakCache)(file => (0, _caching.makeStrongCache)(envName => buildEnvDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors, envName))); const loadFileOverridesDescriptors = (0, _caching.makeWeakCache)(file => (0, _caching.makeStrongCache)(index => buildOverrideDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors, index))); const loadFileOverridesEnvDescriptors = (0, _caching.makeWeakCache)(file => (0, _caching.makeStrongCache)(index => (0, _caching.makeStrongCache)(envName => buildOverrideEnvDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors, index, envName))));

function buildRootDescriptors({

dirname,
options

}, alias, descriptors) {

return descriptors(dirname, options, alias);

}

function buildEnvDescriptors({

dirname,
options

}, alias, descriptors, envName) {

const opts = options.env && options.env[envName];
return opts ? descriptors(dirname, opts, `${alias}.env["${envName}"]`) : null;

}

function buildOverrideDescriptors({

dirname,
options

}, alias, descriptors, index) {

const opts = options.overrides && options.overrides[index];
if (!opts) throw new Error("Assertion failure - missing override");
return descriptors(dirname, opts, `${alias}.overrides[${index}]`);

}

function buildOverrideEnvDescriptors({

dirname,
options

}, alias, descriptors, index, envName) {

const override = options.overrides && options.overrides[index];
if (!override) throw new Error("Assertion failure - missing override");
const opts = override.env && override.env[envName];
return opts ? descriptors(dirname, opts, `${alias}.overrides[${index}].env["${envName}"]`) : null;

}

function makeChainWalker({

root,
env,
overrides,
overridesEnv

}) {

return (input, context, files = new Set()) => {
  const {
    dirname
  } = input;
  const flattenedConfigs = [];
  const rootOpts = root(input);

  if (configIsApplicable(rootOpts, dirname, context)) {
    flattenedConfigs.push(rootOpts);
    const envOpts = env(input, context.envName);

    if (envOpts && configIsApplicable(envOpts, dirname, context)) {
      flattenedConfigs.push(envOpts);
    }

    (rootOpts.options.overrides || []).forEach((_, index) => {
      const overrideOps = overrides(input, index);

      if (configIsApplicable(overrideOps, dirname, context)) {
        flattenedConfigs.push(overrideOps);
        const overrideEnvOpts = overridesEnv(input, index, context.envName);

        if (overrideEnvOpts && configIsApplicable(overrideEnvOpts, dirname, context)) {
          flattenedConfigs.push(overrideEnvOpts);
        }
      }
    });
  }

  if (flattenedConfigs.some(({
    options: {
      ignore,
      only
    }
  }) => shouldIgnore(context, ignore, only, dirname))) {
    return null;
  }

  const chain = emptyChain();

  for (const op of flattenedConfigs) {
    if (!mergeExtendsChain(chain, op.options, dirname, context, files)) {
      return null;
    }

    mergeChainOpts(chain, op);
  }

  return chain;
};

}

function mergeExtendsChain(chain, opts, dirname, context, files) {

if (opts.extends === undefined) return true;
const file = (0, _files.loadConfig)(opts.extends, dirname, context.envName, context.caller);

if (files.has(file)) {
  throw new Error(`Configuration cycle detected loading ${file.filepath}.\n` + `File already loaded following the config chain:\n` + Array.from(files, file => ` - ${file.filepath}`).join("\n"));
}

files.add(file);
const fileChain = loadFileChain(validateExtendFile(file), context, files);
files.delete(file);
if (!fileChain) return false;
mergeChain(chain, fileChain);
return true;

}

function mergeChain(target, source) {

target.options.push(...source.options);
target.plugins.push(...source.plugins);
target.presets.push(...source.presets);
return target;

}

function mergeChainOpts(target, {

options,
plugins,
presets

}) {

target.options.push(options);
target.plugins.push(...plugins());
target.presets.push(...presets());
return target;

}

function emptyChain() {

return {
  options: [],
  presets: [],
  plugins: []
};

}

function normalizeOptions(opts) {

const options = Object.assign({}, opts);
delete options.extends;
delete options.env;
delete options.overrides;
delete options.plugins;
delete options.presets;
delete options.passPerPreset;
delete options.ignore;
delete options.only;
delete options.test;
delete options.include;
delete options.exclude;

if (Object.prototype.hasOwnProperty.call(options, "sourceMap")) {
  options.sourceMaps = options.sourceMap;
  delete options.sourceMap;
}

return options;

}

function dedupDescriptors(items) {

const map = new Map();
const descriptors = [];

for (const item of items) {
  if (typeof item.value === "function") {
    const fnKey = item.value;
    let nameMap = map.get(fnKey);

    if (!nameMap) {
      nameMap = new Map();
      map.set(fnKey, nameMap);
    }

    let desc = nameMap.get(item.name);

    if (!desc) {
      desc = {
        value: item
      };
      descriptors.push(desc);
      if (!item.ownPass) nameMap.set(item.name, desc);
    } else {
      desc.value = item;
    }
  } else {
    descriptors.push({
      value: item
    });
  }
}

return descriptors.reduce((acc, desc) => {
  acc.push(desc.value);
  return acc;
}, []);

}

function configIsApplicable({

options

}, dirname, context) {

return (options.test === undefined || configFieldIsApplicable(context, options.test, dirname)) && (options.include === undefined || configFieldIsApplicable(context, options.include, dirname)) && (options.exclude === undefined || !configFieldIsApplicable(context, options.exclude, dirname));

}

function configFieldIsApplicable(context, test, dirname) {

const patterns = Array.isArray(test) ? test : [test];
return matchesPatterns(context, patterns, dirname);

}

function shouldIgnore(context, ignore, only, dirname) {

if (ignore && matchesPatterns(context, ignore, dirname)) {
  debug("Ignored %o because it matched one of %O from %o", context.filename, ignore, dirname);
  return true;
}

if (only && !matchesPatterns(context, only, dirname)) {
  debug("Ignored %o because it failed to match one of %O from %o", context.filename, only, dirname);
  return true;
}

return false;

}

function matchesPatterns(context, patterns, dirname) {

return patterns.some(pattern => matchPattern(pattern, dirname, context.filename, context));

}

function matchPattern(pattern, dirname, pathToTest, context) {

if (typeof pattern === "function") {
  return !!pattern(pathToTest, {
    dirname,
    envName: context.envName,
    caller: context.caller
  });
}

if (typeof pathToTest !== "string") {
  throw new Error(`Configuration contains string/RegExp pattern, but no filename was passed to Babel`);
}

if (typeof pattern === "string") {
  pattern = (0, _patternToRegex.default)(pattern, dirname);
}

return pattern.test(pathToTest);

}