import path from 'path';
import yaml from 'js-yaml';
import lodash from 'lodash';
import requirePackageName from 'require-package-name';
import { evaluate } from '../utils';

function parse(content) {
  try {
    return JSON.parse(content);
  } catch (error) {
    // not JSON format
  }

  try {
    return yaml.safeLoad(content);
  } catch (error) {
    // not YAML format
  }

  try {
    return evaluate(`module.exports = ${content}`);
  } catch (error) {
    // not valid JavaScript code
  }

  // parse fail, return nothing
  return {};
}

function wrapToArray(obj) {
  if (!obj) {
    return [];
  } else if (lodash.isArray(obj)) {
    return obj;
  }

  return [obj];
}

function isEslintConfigAnAbsolutePath(specifier) {
  return path.isAbsolute(specifier);
}

function isEslintConfigARelativePath(specifier) {
  return lodash.startsWith(specifier, './') || lodash.startsWith(specifier, '../');
}

function isEslintConfigAScopedModule(specifier) {
  return lodash.startsWith(specifier, '@');
}

function isEslintConfigAFullyQualifiedModuleName(specifier) {
  return lodash.startsWith(specifier, 'eslint-config-');
}

function resolvePresetPackage(preset, rootDir) {
  // inspired from https://github.com/eslint/eslint/blob/5b4a94e26d0ef247fe222dacab5749805d9780dd/lib/config/config-file.js#L347
  if (isEslintConfigAnAbsolutePath(preset)) {
    return preset;
  }
  if (isEslintConfigARelativePath(preset)) {
    return path.resolve(rootDir, preset);
  }
  if (isEslintConfigAScopedModule(preset)) {
    const scope = preset.substring(0, preset.indexOf('/'));
    const module = preset.substring(preset.indexOf('/') + 1);

    if (isEslintConfigAFullyQualifiedModuleName(module)) {
      return preset;
    }
    return `${scope}/eslint-config-${module}`;
  }
  if (isEslintConfigAFullyQualifiedModuleName(preset)) {
    return preset;
  }
  return `eslint-config-${preset}`;
}

function loadConfig(preset, rootDir) {
  const presetPath = path.isAbsolute(preset)
    ? preset
    : path.resolve(rootDir, 'node_modules', preset);

  try {
    return require(presetPath); // eslint-disable-line global-require
  } catch (error) {
    return {}; // silently return nothing
  }
}

function checkConfig(config, rootDir) {
  const parser = wrapToArray(config.parser);
  const plugins = wrapToArray(config.plugins).map(plugin => `eslint-plugin-${plugin}`);

  const presets = wrapToArray(config.extends)
    .filter(preset => preset !== 'eslint:recommended')
    .map(preset => resolvePresetPackage(preset, rootDir));

  const presetPackages = presets
    .filter(preset => !path.isAbsolute(preset))
    .map(requirePackageName);

  const presetDeps = lodash(presets)
    .map(preset => loadConfig(preset, rootDir))
    .map(presetConfig => checkConfig(presetConfig, rootDir))
    .flatten()
    .value();

  return lodash.union(parser, plugins, presetPackages, presetDeps);
}

export default function parseESLint(content, filename, deps, rootDir) {
  const basename = path.basename(filename);
  if (/^\.eslintrc(\.json|\.js|\.yml|\.yaml)?$/.test(basename)) {
    const config = parse(content);
    return checkConfig(config, rootDir);
  }

  return [];
}

@@ -915,32 +915,137 @@
 n isEslintConfig
+FromAPlugin(specifier) %7B%0A  return lodash.startsWith(specifier, 'plugin:');%0A%7D%0A%0Afunction isEslintConfigFrom
 AScopedModule(sp
@@ -1117,32 +1117,36 @@
 n isEslintConfig
+From
 AFullyQualifiedM
@@ -1156,32 +1156,40 @@
 leName(specifier
+, prefix
 ) %7B%0A  return lod
@@ -1218,24 +1218,14 @@
 er, 
-'eslint-config-'
+prefix
 );%0A%7D
@@ -1564,36 +1564,262 @@
 t);%0A  %7D%0A
+%0A
   
-if (isEslintConfig
+const %7B prefix, specifier %7D = (%0A    isEslintConfigFromAPlugin(preset)%0A    ? %7B prefix: 'eslint-plugin-', specifier: preset.substring(preset.indexOf(':') + 1) %7D%0A    : %7B prefix: 'eslint-config-', specifier: preset %7D%0A  );%0A%0A  if (isEslintConfigFrom
 AScopedM
@@ -1824,22 +1824,25 @@
 dModule(
-preset
+specifier
 )) %7B%0A   
@@ -1852,30 +1852,33 @@
 nst scope = 
-preset
+specifier
 .substring(0
@@ -1879,22 +1879,25 @@
 ring(0, 
-preset
+specifier
 .indexOf
@@ -1923,22 +1923,25 @@
 odule = 
-preset
+specifier
 .substri
@@ -1935,38 +1935,41 @@
 ifier.substring(
-preset
+specifier
 .indexOf('/') + 
@@ -1987,32 +1987,36 @@
  (isEslintConfig
+From
 AFullyQualifiedM
@@ -2031,16 +2031,24 @@
 e(module
+, prefix
 )) %7B%0A   
@@ -2053,30 +2053,33 @@
      return 
-preset
+specifier
 ;%0A    %7D%0A    
@@ -2095,30 +2095,25 @@
 %7Bscope%7D/
-eslint-config-
+$%7Bprefix%7D
 $%7Bmodule
@@ -2140,16 +2140,20 @@
 ntConfig
+From
 AFullyQu
@@ -2170,22 +2170,33 @@
 uleName(
-preset
+specifier, prefix
 )) %7B%0A   
@@ -2195,38 +2195,41 @@
 )) %7B%0A    return 
-preset
+specifier
 ;%0A  %7D%0A  return %60
@@ -2232,30 +2232,28 @@
 rn %60
-eslint-config-$%7Bpreset
+$%7Bprefix%7D$%7Bspecifier
 %7D%60;%0A

Add support for eslint’s ‘plugin:’ prefixed presets