'use strict';

var _fs = require('fs');

var _fs2 = _interopRequireDefault(_fs);

var _pkgUp = require('pkg-up');

var _pkgUp2 = _interopRequireDefault(_pkgUp);

var _minimatch = require('minimatch');

var _minimatch2 = _interopRequireDefault(_minimatch);

var _importType = require('../core/importType');

var _importType2 = _interopRequireDefault(_importType);

var _staticRequire = require('../core/staticRequire');

var _staticRequire2 = _interopRequireDefault(_staticRequire);

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

function getDependencies(context) {
  var filepath = _pkgUp2.default.sync(context.getFilename());
  if (!filepath) {
    return null;
  }

  try {
    var packageContent = JSON.parse(_fs2.default.readFileSync(filepath, 'utf8'));
    return {
      dependencies: packageContent.dependencies || {},
      devDependencies: packageContent.devDependencies || {},
      optionalDependencies: packageContent.optionalDependencies || {},
      peerDependencies: packageContent.peerDependencies || {}
    };
  } catch (e) {
    return null;
  }
}

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

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

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

function reportIfMissing(context, deps, depsOptions, node, name) {
  if ((0, _importType2.default)(name, context) !== 'external') {
    return;
  }
  var splitName = name.split('/');
  var packageName = splitName[0][0] === '@' ? splitName.slice(0, 2).join('/') : splitName[0];

  var isInDeps = deps.dependencies[packageName] !== undefined;
  var isInDevDeps = deps.devDependencies[packageName] !== undefined;
  var isInOptDeps = deps.optionalDependencies[packageName] !== undefined;
  var isInPeerDeps = deps.peerDependencies[packageName] !== undefined;

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

  if (isInDevDeps && !depsOptions.allowDevDeps) {
    context.report(node, devDepErrorMessage(packageName));
    return;
  }

  if (isInOptDeps && !depsOptions.allowOptDeps) {
    context.report(node, optDepErrorMessage(packageName));
    return;
  }

  context.report(node, missingErrorMessage(packageName));
}

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);
  });
}

module.exports = function (context) {
  var options = context.options[0] || {};
  var filename = context.getFilename();
  var deps = getDependencies(context);

  if (!deps) {
    return {};
  }

  var depsOptions = {
    allowDevDeps: testConfig(options.devDependencies, filename) !== false,
    allowOptDeps: testConfig(options.optionalDependencies, filename) !== false,
    allowPeerDeps: testConfig(options.peerDependencies, filename) !== false
  };

  // todo: use module visitor from module-utils core
  return {
    ImportDeclaration: function ImportDeclaration(node) {
      reportIfMissing(context, deps, depsOptions, node, node.source.value);
    },
    CallExpression: function handleRequires(node) {
      if ((0, _staticRequire2.default)(node)) {
        reportIfMissing(context, deps, depsOptions, node, node.arguments[0].value);
      }
    }
  };
};

module.exports.schema = [{
  'type': 'object',
  'properties': {
    'devDependencies': { 'type': ['boolean', 'array'] },
    'optionalDependencies': { 'type': ['boolean', 'array'] },
    'peerDependencies': { 'type': ['boolean', 'array'] }
  },
  'additionalProperties': false
}];
//# sourceMappingURL=data:application/json;base64,[encoded data, 9992 characters]