'use strict';var _slicedToArray = function () {function sliceIterator(arr, i) {var _arr = [];var _n = true;var _d = false;var _e = undefined;try {for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {_arr.push(_s.value);if (i && _arr.length === i) break;}} catch (err) {_d = true;_e = err;} finally {try {if (!_n && _i["return"]) _i["return"]();} finally {if (_d) throw _e;}}return _arr;}return function (arr, i) {if (Array.isArray(arr)) {return arr;} else if (Symbol.iterator in Object(arr)) {return sliceIterator(arr, i);} else {throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}();var _path = require('path');var _path2 = _interopRequireDefault(_path);
var _fs = require('fs');var _fs2 = _interopRequireDefault(_fs);
var _pkgUp = require('eslint-module-utils/pkgUp');var _pkgUp2 = _interopRequireDefault(_pkgUp);
var _minimatch = require('minimatch');var _minimatch2 = _interopRequireDefault(_minimatch);
var _resolve = require('eslint-module-utils/resolve');var _resolve2 = _interopRequireDefault(_resolve);
var _moduleVisitor = require('eslint-module-utils/moduleVisitor');var _moduleVisitor2 = _interopRequireDefault(_moduleVisitor);
var _importType = require('../core/importType');var _importType2 = _interopRequireDefault(_importType);
var _packagePath = require('../core/packagePath');
var _docsUrl = require('../docsUrl');var _docsUrl2 = _interopRequireDefault(_docsUrl);function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { 'default': obj };}

var depFieldCache = new Map();

function hasKeys() {var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  return Object.keys(obj).length > 0;
}

function arrayOrKeys(arrayOrObject) {
  return Array.isArray(arrayOrObject) ? arrayOrObject : Object.keys(arrayOrObject);
}

function readJSON(jsonPath, throwException) {
  try {
    return JSON.parse(_fs2['default'].readFileSync(jsonPath, 'utf8'));
  } catch (err) {
    if (throwException) {
      throw err;
    }
  }
}

function extractDepFields(pkg) {
  return {
    dependencies: pkg.dependencies || {},
    devDependencies: pkg.devDependencies || {},
    optionalDependencies: pkg.optionalDependencies || {},
    peerDependencies: pkg.peerDependencies || {},
    // BundledDeps should be in the form of an array, but object notation is also supported by
    // `npm`, so we convert it to an array if it is an object
    bundledDependencies: arrayOrKeys(pkg.bundleDependencies || pkg.bundledDependencies || []) };

}

function getPackageDepFields(packageJsonPath, throwAtRead) {
  if (!depFieldCache.has(packageJsonPath)) {
    var depFields = extractDepFields(readJSON(packageJsonPath, throwAtRead));
    depFieldCache.set(packageJsonPath, depFields);
  }

  return depFieldCache.get(packageJsonPath);
}

function getDependencies(context, packageDir) {
  var paths = [];
  try {
    var packageContent = {
      dependencies: {},
      devDependencies: {},
      optionalDependencies: {},
      peerDependencies: {},
      bundledDependencies: [] };


    if (packageDir && packageDir.length > 0) {
      if (!Array.isArray(packageDir)) {
        paths = [_path2['default'].resolve(packageDir)];
      } else {
        paths = packageDir.map(function (dir) {return _path2['default'].resolve(dir);});
      }
    }

    if (paths.length > 0) {
      // use rule config to find package.json
      paths.forEach(function (dir) {
        var packageJsonPath = _path2['default'].join(dir, 'package.json');
        var _packageContent = getPackageDepFields(packageJsonPath, true);
        Object.keys(packageContent).forEach(function (depsKey) {return (
            Object.assign(packageContent[depsKey], _packageContent[depsKey]));});

      });
    } else {
      var packageJsonPath = (0, _pkgUp2['default'])({
        cwd: context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename(),
        normalize: false });


      // use closest package.json
      Object.assign(
      packageContent,
      getPackageDepFields(packageJsonPath, false));

    }

    if (![
    packageContent.dependencies,
    packageContent.devDependencies,
    packageContent.optionalDependencies,
    packageContent.peerDependencies,
    packageContent.bundledDependencies].
    some(hasKeys)) {
      return null;
    }

    return packageContent;
  } catch (e) {
    if (paths.length > 0 && e.code === 'ENOENT') {
      context.report({
        message: 'The package.json file could not be found.',
        loc: { line: 0, column: 0 } });

    }
    if (e.name === 'JSONError' || e instanceof SyntaxError) {
      context.report({
        message: 'The package.json file could not be parsed: ' + e.message,
        loc: { line: 0, column: 0 } });

    }

    return null;
  }
}

function missingErrorMessage(packageName) {
  return '\'' + String(packageName) + '\' should be listed in the project\'s dependencies. ' + ('Run \'npm i -S ' + String(
  packageName) + '\' to add it');
}

function devDepErrorMessage(packageName) {
  return '\'' + String(packageName) + '\' should be listed in the project\'s dependencies, not devDependencies.';
}

function optDepErrorMessage(packageName) {
  return '\'' + String(packageName) + '\' should be listed in the project\'s dependencies, ' + 'not optionalDependencies.';

}

function getModuleOriginalName(name) {var _name$split =
  name.split('/'),_name$split2 = _slicedToArray(_name$split, 2),first = _name$split2[0],second = _name$split2[1];
  return first.startsWith('@') ? String(first) + '/' + String(second) : first;
}

function getModuleRealName(resolved) {
  return (0, _packagePath.getFilePackageName)(resolved);
}

function checkDependencyDeclaration(deps, packageName, declarationStatus) {
  var newDeclarationStatus = declarationStatus || {
    isInDeps: false,
    isInDevDeps: false,
    isInOptDeps: false,
    isInPeerDeps: false,
    isInBundledDeps: false };


  // in case of sub package.json inside a module
  // check the dependencies on all hierarchy
  var packageHierarchy = [];
  var packageNameParts = packageName ? packageName.split('/') : [];
  packageNameParts.forEach(function (namePart, index) {
    if (!namePart.startsWith('@')) {
      var ancestor = packageNameParts.slice(0, index + 1).join('/');
      packageHierarchy.push(ancestor);
    }
  });

  return packageHierarchy.reduce(function (result, ancestorName) {
    return {
      isInDeps: result.isInDeps || deps.dependencies[ancestorName] !== undefined,
      isInDevDeps: result.isInDevDeps || deps.devDependencies[ancestorName] !== undefined,
      isInOptDeps: result.isInOptDeps || deps.optionalDependencies[ancestorName] !== undefined,
      isInPeerDeps: result.isInPeerDeps || deps.peerDependencies[ancestorName] !== undefined,
      isInBundledDeps:
      result.isInBundledDeps || deps.bundledDependencies.indexOf(ancestorName) !== -1 };

  }, newDeclarationStatus);
}

function reportIfMissing(context, deps, depsOptions, node, name) {
  // Do not report when importing types unless option is enabled
  if (
  !depsOptions.verifyTypeImports && (
  node.importKind === 'type' || node.importKind === 'typeof'))
  {
    return;
  }

  var typeOfImport = (0, _importType2['default'])(name, context);

  if (
  typeOfImport !== 'external' && (
  typeOfImport !== 'internal' || !depsOptions.verifyInternalDeps))
  {
    return;
  }

  var resolved = (0, _resolve2['default'])(name, context);
  if (!resolved) {return;}

  var importPackageName = getModuleOriginalName(name);
  var declarationStatus = checkDependencyDeclaration(deps, importPackageName);

  if (
  declarationStatus.isInDeps ||
  depsOptions.allowDevDeps && declarationStatus.isInDevDeps ||
  depsOptions.allowPeerDeps && declarationStatus.isInPeerDeps ||
  depsOptions.allowOptDeps && declarationStatus.isInOptDeps ||
  depsOptions.allowBundledDeps && declarationStatus.isInBundledDeps)
  {
    return;
  }

  // test the real name from the resolved package.json
  // if not aliased imports (alias/react for example), importPackageName can be misinterpreted
  var realPackageName = getModuleRealName(resolved);
  if (realPackageName && realPackageName !== importPackageName) {
    declarationStatus = checkDependencyDeclaration(deps, realPackageName, declarationStatus);

    if (
    declarationStatus.isInDeps ||
    depsOptions.allowDevDeps && declarationStatus.isInDevDeps ||
    depsOptions.allowPeerDeps && declarationStatus.isInPeerDeps ||
    depsOptions.allowOptDeps && declarationStatus.isInOptDeps ||
    depsOptions.allowBundledDeps && declarationStatus.isInBundledDeps)
    {
      return;
    }
  }

  if (declarationStatus.isInDevDeps && !depsOptions.allowDevDeps) {
    context.report(node, devDepErrorMessage(realPackageName || importPackageName));
    return;
  }

  if (declarationStatus.isInOptDeps && !depsOptions.allowOptDeps) {
    context.report(node, optDepErrorMessage(realPackageName || importPackageName));
    return;
  }

  context.report(node, missingErrorMessage(realPackageName || importPackageName));
}

function testConfig(config, filename) {
  // Simplest configuration first, either a boolean or nothing.
  if (typeof config === 'boolean' || typeof config === 'undefined') {
    return config;
  }
  // Array of globs.
  return config.some(function (c) {return (
      (0, _minimatch2['default'])(filename, c) ||
      (0, _minimatch2['default'])(filename, _path2['default'].join(process.cwd(), c)));});

}

module.exports = {
  meta: {
    type: 'problem',
    docs: {
      category: 'Helpful warnings',
      description: 'Forbid the use of extraneous packages.',
      url: (0, _docsUrl2['default'])('no-extraneous-dependencies') },


    schema: [
    {
      'type': 'object',
      'properties': {
        'devDependencies': { 'type': ['boolean', 'array'] },
        'optionalDependencies': { 'type': ['boolean', 'array'] },
        'peerDependencies': { 'type': ['boolean', 'array'] },
        'bundledDependencies': { 'type': ['boolean', 'array'] },
        'packageDir': { 'type': ['string', 'array'] },
        'includeInternal': { 'type': ['boolean'] },
        'includeTypes': { 'type': ['boolean'] } },

      'additionalProperties': false }] },




  create: function () {function create(context) {
      var options = context.options[0] || {};
      var filename = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
      var deps = getDependencies(context, options.packageDir) || extractDepFields({});

      var depsOptions = {
        allowDevDeps: testConfig(options.devDependencies, filename) !== false,
        allowOptDeps: testConfig(options.optionalDependencies, filename) !== false,
        allowPeerDeps: testConfig(options.peerDependencies, filename) !== false,
        allowBundledDeps: testConfig(options.bundledDependencies, filename) !== false,
        verifyInternalDeps: !!options.includeInternal,
        verifyTypeImports: !!options.includeTypes };


      return (0, _moduleVisitor2['default'])(function (source, node) {
        reportIfMissing(context, deps, depsOptions, node, source.value);
      }, { commonjs: true });
    }return create;}(),

  'Program:exit': function () {function ProgramExit() {
      depFieldCache.clear();
    }return ProgramExit;}() };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,[encoded data, 25432 characters]