“use strict”;

Object.defineProperty(exports, “__esModule”, {

value: true

}); exports.validate = validate;

var _plugin = _interopRequireDefault(require(“../plugin”));

var _removed = _interopRequireDefault(require(“./removed”));

var _optionAssertions = require(“./option-assertions”);

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

const ROOT_VALIDATORS = {

cwd: _optionAssertions.assertString,
root: _optionAssertions.assertString,
rootMode: _optionAssertions.assertRootMode,
configFile: _optionAssertions.assertConfigFileSearch,
caller: _optionAssertions.assertCallerMetadata,
filename: _optionAssertions.assertString,
filenameRelative: _optionAssertions.assertString,
code: _optionAssertions.assertBoolean,
ast: _optionAssertions.assertBoolean,
envName: _optionAssertions.assertString

}; const BABELRC_VALIDATORS = {

babelrc: _optionAssertions.assertBoolean,
babelrcRoots: _optionAssertions.assertBabelrcSearch

}; const NONPRESET_VALIDATORS = {

extends: _optionAssertions.assertString,
ignore: _optionAssertions.assertIgnoreList,
only: _optionAssertions.assertIgnoreList

}; const COMMON_VALIDATORS = {

inputSourceMap: _optionAssertions.assertInputSourceMap,
presets: _optionAssertions.assertPluginList,
plugins: _optionAssertions.assertPluginList,
passPerPreset: _optionAssertions.assertBoolean,
env: assertEnvSet,
overrides: assertOverridesList,
test: _optionAssertions.assertConfigApplicableTest,
include: _optionAssertions.assertConfigApplicableTest,
exclude: _optionAssertions.assertConfigApplicableTest,
retainLines: _optionAssertions.assertBoolean,
comments: _optionAssertions.assertBoolean,
shouldPrintComment: _optionAssertions.assertFunction,
compact: _optionAssertions.assertCompact,
minified: _optionAssertions.assertBoolean,
auxiliaryCommentBefore: _optionAssertions.assertString,
auxiliaryCommentAfter: _optionAssertions.assertString,
sourceType: _optionAssertions.assertSourceType,
wrapPluginVisitorMethod: _optionAssertions.assertFunction,
highlightCode: _optionAssertions.assertBoolean,
sourceMaps: _optionAssertions.assertSourceMaps,
sourceMap: _optionAssertions.assertSourceMaps,
sourceFileName: _optionAssertions.assertString,
sourceRoot: _optionAssertions.assertString,
getModuleId: _optionAssertions.assertFunction,
moduleRoot: _optionAssertions.assertString,
moduleIds: _optionAssertions.assertBoolean,
moduleId: _optionAssertions.assertString,
parserOpts: _optionAssertions.assertObject,
generatorOpts: _optionAssertions.assertObject

};

function getSource(loc) {

return loc.type === "root" ? loc.source : getSource(loc.parent);

}

function validate(type, opts) {

return validateNested({
  type: "root",
  source: type
}, opts);

}

function validateNested(loc, opts) {

const type = getSource(loc);
assertNoDuplicateSourcemap(opts);
Object.keys(opts).forEach(key => {
  const optLoc = {
    type: "option",
    name: key,
    parent: loc
  };

  if (type === "preset" && NONPRESET_VALIDATORS[key]) {
    throw new Error(`${(0, _optionAssertions.msg)(optLoc)} is not allowed in preset options`);
  }

  if (type !== "arguments" && ROOT_VALIDATORS[key]) {
    throw new Error(`${(0, _optionAssertions.msg)(optLoc)} is only allowed in root programmatic options`);
  }

  if (type !== "arguments" && type !== "configfile" && BABELRC_VALIDATORS[key]) {
    if (type === "babelrcfile" || type === "extendsfile") {
      throw new Error(`${(0, _optionAssertions.msg)(optLoc)} is not allowed in .babelrc or "extends"ed files, only in root programmatic options, ` + `or babel.config.js/config file options`);
    }

    throw new Error(`${(0, _optionAssertions.msg)(optLoc)} is only allowed in root programmatic options, or babel.config.js/config file options`);
  }

  const validator = COMMON_VALIDATORS[key] || NONPRESET_VALIDATORS[key] || BABELRC_VALIDATORS[key] || ROOT_VALIDATORS[key] || throwUnknownError;
  validator(optLoc, opts[key]);
});
return opts;

}

function throwUnknownError(loc) {

const key = loc.name;

if (_removed.default[key]) {
  const {
    message,
    version = 5
  } = _removed.default[key];
  throw new ReferenceError(`Using removed Babel ${version} option: ${(0, _optionAssertions.msg)(loc)} - ${message}`);
} else {
  const unknownOptErr = `Unknown option: ${(0, _optionAssertions.msg)(loc)}. Check out https://babeljs.io/docs/en/babel-core/#options for more information about options.`;
  throw new ReferenceError(unknownOptErr);
}

}

function has(obj, key) {

return Object.prototype.hasOwnProperty.call(obj, key);

}

function assertNoDuplicateSourcemap(opts) {

if (has(opts, "sourceMap") && has(opts, "sourceMaps")) {
  throw new Error(".sourceMap is an alias for .sourceMaps, cannot use both");
}

}

function assertEnvSet(loc, value) {

if (loc.parent.type === "env") {
  throw new Error(`${(0, _optionAssertions.msg)(loc)} is not allowed inside of another .env block`);
}

const parent = loc.parent;
const obj = (0, _optionAssertions.assertObject)(loc, value);

if (obj) {
  for (const envName of Object.keys(obj)) {
    const env = (0, _optionAssertions.assertObject)((0, _optionAssertions.access)(loc, envName), obj[envName]);
    if (!env) continue;
    const envLoc = {
      type: "env",
      name: envName,
      parent
    };
    validateNested(envLoc, env);
  }
}

return obj;

}

function assertOverridesList(loc, value) {

if (loc.parent.type === "env") {
  throw new Error(`${(0, _optionAssertions.msg)(loc)} is not allowed inside an .env block`);
}

if (loc.parent.type === "overrides") {
  throw new Error(`${(0, _optionAssertions.msg)(loc)} is not allowed inside an .overrides block`);
}

const parent = loc.parent;
const arr = (0, _optionAssertions.assertArray)(loc, value);

if (arr) {
  for (const [index, item] of arr.entries()) {
    const objLoc = (0, _optionAssertions.access)(loc, index);
    const env = (0, _optionAssertions.assertObject)(objLoc, item);
    if (!env) throw new Error(`${(0, _optionAssertions.msg)(objLoc)} must be an object`);
    const overridesLoc = {
      type: "overrides",
      index,
      parent
    };
    validateNested(overridesLoc, env);
  }
}

return arr;

}