“use strict”;

Object.defineProperty(exports, “__esModule”, {

value: true

}); exports.createCachedDescriptors = createCachedDescriptors; exports.createUncachedDescriptors = createUncachedDescriptors; exports.createDescriptor = createDescriptor;

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

var _item = require(“./item”);

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

function isEqualDescriptor(a, b) {

return a.name === b.name && a.value === b.value && a.options === b.options && a.dirname === b.dirname && a.alias === b.alias && a.ownPass === b.ownPass && (a.file && a.file.request) === (b.file && b.file.request) && (a.file && a.file.resolved) === (b.file && b.file.resolved);

}

function createCachedDescriptors(dirname, options, alias) {

const {
  plugins,
  presets,
  passPerPreset
} = options;
return {
  options,
  plugins: plugins ? () => createCachedPluginDescriptors(plugins, dirname)(alias) : () => [],
  presets: presets ? () => createCachedPresetDescriptors(presets, dirname)(alias)(!!passPerPreset) : () => []
};

}

function createUncachedDescriptors(dirname, options, alias) {

let plugins;
let presets;
return {
  options,
  plugins: () => {
    if (!plugins) {
      plugins = createPluginDescriptors(options.plugins || [], dirname, alias);
    }

    return plugins;
  },
  presets: () => {
    if (!presets) {
      presets = createPresetDescriptors(options.presets || [], dirname, alias, !!options.passPerPreset);
    }

    return presets;
  }
};

}

const PRESET_DESCRIPTOR_CACHE = new WeakMap(); const createCachedPresetDescriptors = (0, _caching.makeWeakCache)((items, cache) => {

const dirname = cache.using(dir => dir);
return (0, _caching.makeStrongCache)(alias => (0, _caching.makeStrongCache)(passPerPreset => createPresetDescriptors(items, dirname, alias, passPerPreset).map(desc => loadCachedDescriptor(PRESET_DESCRIPTOR_CACHE, desc))));

}); const PLUGIN_DESCRIPTOR_CACHE = new WeakMap(); const createCachedPluginDescriptors = (0, _caching.makeWeakCache)((items, cache) => {

const dirname = cache.using(dir => dir);
return (0, _caching.makeStrongCache)(alias => createPluginDescriptors(items, dirname, alias).map(desc => loadCachedDescriptor(PLUGIN_DESCRIPTOR_CACHE, desc)));

}); const DEFAULT_OPTIONS = {};

function loadCachedDescriptor(cache, desc) {

const {
  value,
  options = DEFAULT_OPTIONS
} = desc;
if (options === false) return desc;
let cacheByOptions = cache.get(value);

if (!cacheByOptions) {
  cacheByOptions = new WeakMap();
  cache.set(value, cacheByOptions);
}

let possibilities = cacheByOptions.get(options);

if (!possibilities) {
  possibilities = [];
  cacheByOptions.set(options, possibilities);
}

if (possibilities.indexOf(desc) === -1) {
  const matches = possibilities.filter(possibility => isEqualDescriptor(possibility, desc));

  if (matches.length > 0) {
    return matches[0];
  }

  possibilities.push(desc);
}

return desc;

}

function createPresetDescriptors(items, dirname, alias, passPerPreset) {

return createDescriptors("preset", items, dirname, alias, passPerPreset);

}

function createPluginDescriptors(items, dirname, alias) {

return createDescriptors("plugin", items, dirname, alias);

}

function createDescriptors(type, items, dirname, alias, ownPass) {

const descriptors = items.map((item, index) => createDescriptor(item, dirname, {
  type,
  alias: `${alias}$${index}`,
  ownPass: !!ownPass
}));
assertNoDuplicates(descriptors);
return descriptors;

}

function createDescriptor(pair, dirname, {

type,
alias,
ownPass

}) {

const desc = (0, _item.getItemDescriptor)(pair);

if (desc) {
  return desc;
}

let name;
let options;
let value = pair;

if (Array.isArray(value)) {
  if (value.length === 3) {
    [value, options, name] = value;
  } else {
    [value, options] = value;
  }
}

let file = undefined;
let filepath = null;

if (typeof value === "string") {
  if (typeof type !== "string") {
    throw new Error("To resolve a string-based item, the type of item must be given");
  }

  const resolver = type === "plugin" ? _files.loadPlugin : _files.loadPreset;
  const request = value;
  ({
    filepath,
    value
  } = resolver(value, dirname));
  file = {
    request,
    resolved: filepath
  };
}

if (!value) {
  throw new Error(`Unexpected falsy value: ${String(value)}`);
}

if (typeof value === "object" && value.__esModule) {
  if (value.default) {
    value = value.default;
  } else {
    throw new Error("Must export a default export when using ES6 modules.");
  }
}

if (typeof value !== "object" && typeof value !== "function") {
  throw new Error(`Unsupported format: ${typeof value}. Expected an object or a function.`);
}

if (filepath !== null && typeof value === "object" && value) {
  throw new Error(`Plugin/Preset files are not allowed to export objects, only functions. In ${filepath}`);
}

return {
  name,
  alias: filepath || alias,
  value,
  options,
  dirname,
  ownPass,
  file
};

}

function assertNoDuplicates(items) {

const map = new Map();

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

  if (!nameMap) {
    nameMap = new Set();
    map.set(item.value, nameMap);
  }

  if (nameMap.has(item.name)) {
    const conflicts = items.filter(i => i.value === item.value);
    throw new Error([`Duplicate plugin/preset detected.`, `If you'd like to use two separate instances of a plugin,`, `they need separate names, e.g.`, ``, `  plugins: [`, `    ['some-plugin', {}],`, `    ['some-plugin', {}, 'some unique name'],`, `  ]`, ``, `Duplicates detected are:`, `${JSON.stringify(conflicts, null, 2)}`].join("\n"));
  }

  nameMap.add(item.name);
}

}