"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.getAppConfiguration = getAppConfiguration;
exports.getMainConfiguration = getMainConfiguration;
exports.getRendererConfiguration = getRendererConfiguration;
exports.getDllConfiguration = getDllConfiguration;
exports.getTestConfiguration = getTestConfiguration;
exports.createConfigurator = createConfigurator;
exports.configure = configure;
exports.WebpackConfigurator = void 0;

function BluebirdPromise() {
  const data = _interopRequireWildcard(require("bluebird"));

  BluebirdPromise = function () {
    return data;
  };

  return data;
}

function _dotenv() {
  const data = require("dotenv");

  _dotenv = function () {
    return data;
  };

  return data;
}

function _dotenvExpand() {
  const data = _interopRequireDefault(require("dotenv-expand"));

  _dotenvExpand = function () {
    return data;
  };

  return data;
}

function _fsExtra() {
  const data = require("fs-extra");

  _fsExtra = function () {
    return data;
  };

  return data;
}

function _lazyVal() {
  const data = require("lazy-val");

  _lazyVal = function () {
    return data;
  };

  return data;
}

var path = _interopRequireWildcard(require("path"));

function _readConfigFile() {
  const data = require("read-config-file");

  _readConfigFile = function () {
    return data;
  };

  return data;
}

function _deepAssign() {
  const data = require("read-config-file/out/deepAssign");

  _deepAssign = function () {
    return data;
  };

  return data;
}

require("source-map-support/register");

function _webpackMerge() {
  const data = _interopRequireDefault(require("webpack-merge"));

  _webpackMerge = function () {
    return data;
  };

  return data;
}

function _config() {
  const data = require("./config");

  _config = function () {
    return data;
  };

  return data;
}

function _ts() {
  const data = require("./configurators/ts");

  _ts = function () {
    return data;
  };

  return data;
}

function _vue() {
  const data = require("./configurators/vue/vue");

  _vue = function () {
    return data;
  };

  return data;
}

function _BaseTarget() {
  const data = require("./targets/BaseTarget");

  _BaseTarget = function () {
    return data;
  };

  return data;
}

function _MainTarget() {
  const data = require("./targets/MainTarget");

  _MainTarget = function () {
    return data;
  };

  return data;
}

function _RendererTarget() {
  const data = require("./targets/RendererTarget");

  _RendererTarget = function () {
    return data;
  };

  return data;
}

function _util() {
  const data = require("./util");

  _util = function () {
    return data;
  };

  return data;
}

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

function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

const _debug = require("debug"); // noinspection JSUnusedGlobalSymbols


function getAppConfiguration(env) {
  return BluebirdPromise().filter([configure("main", env), configure("renderer", env)], it => it != null);
} // noinspection JSUnusedGlobalSymbols


function getMainConfiguration(env) {
  return configure("main", env);
} // noinspection JSUnusedGlobalSymbols


function getRendererConfiguration(env) {
  return configure("renderer", env);
} // in the future, if need, isRenderer = true arg can be added
// noinspection JSUnusedGlobalSymbols


function getDllConfiguration(env) {
  return configure("renderer-dll", env);
} // noinspection JSUnusedGlobalSymbols


async function getTestConfiguration(env) {
  const configurator = await createConfigurator("test", env);
  return await configurator.configure({
    testComponents: path.join(process.cwd(), "src/renderer/components/testComponents.ts")
  });
}

class WebpackConfigurator {
  // electronWebpackConfiguration expected to be resolved (use getElectronWebpackConfiguration())
  constructor(type, env, electronWebpackConfiguration, metadata) {
    this.type = type;
    this.env = env;
    this.electronWebpackConfiguration = electronWebpackConfiguration;
    this.metadata = metadata;
    this.electronVersionPromise = new (_lazyVal().Lazy)(() => getInstalledElectronVersion(this.projectDir));
    this.isTest = this.type === "test";
    this.debug = _debug(`electron-webpack:${this.type}`);
    this._configuration = null;
    this.rules = [];
    this.plugins = []; // js must be first - e.g. iView has two files loading-bar.js and loading-bar.vue - when we require "loading-bar", js file must be resolved and not vue

    this.extensions = [".js", ".json", ".node"];
    this._electronVersion = null;
    this.entryFiles = [];

    if (metadata.dependencies == null) {
      metadata.dependencies = {};
    }

    if (metadata.devDependencies == null) {
      metadata.devDependencies = {};
    }

    this.projectDir = electronWebpackConfiguration.projectDir;
    this.isRenderer = type.startsWith("renderer");
    process.env.BABEL_ENV = type;
    this.isProduction = this.env.production == null ? process.env.NODE_ENV === "production" : this.env.production;
    this.debug(`isProduction: ${this.isProduction}`);
    this.sourceDir = this.getSourceDirectory(this.type);
    this.staticSourceDirectory = this.electronWebpackConfiguration.staticSourceDirectory;
    this.commonSourceDirectory = this.electronWebpackConfiguration.commonSourceDirectory;
    this.commonDistDirectory = this.electronWebpackConfiguration.commonDistDirectory;
    this.rendererTemplate = this.electronWebpackConfiguration.renderer && this.electronWebpackConfiguration.renderer.template || "src/index.ejs";
  }

  get config() {
    return this._configuration;
  }

  get electronVersion() {
    return this._electronVersion;
  }
  /**
   * Returns null if code processing for type is disabled.
   */


  getSourceDirectory(type) {
    const part = this.getPartConfiguration(type);

    if (part === null || part != null && part.sourceDirectory === null) {
      // part or sourceDirectory is explicitly set to null
      return null;
    }

    const result = part == null ? null : part.sourceDirectory;

    if (result == null) {
      return path.join(this.projectDir, "src", type.startsWith("renderer") || type === "test" ? "renderer" : type);
    } else {
      return path.resolve(this.projectDir, result);
    }
  }

  getPartConfiguration(type) {
    if (type === "main") {
      return this.electronWebpackConfiguration.main;
    } else {
      return this.electronWebpackConfiguration.renderer;
    }
  }

  hasDependency(name) {
    return name in this.metadata.dependencies || this.hasDevDependency(name);
  }

  hasDevDependency(name) {
    return name in this.metadata.devDependencies;
  }
  /**
   * Returns the names of devDependencies that match a given string or regex.
   * If no matching dependencies are found, an empty array is returned.
   *
   * @return list of matching dependency names, e.g. `["@babel/preset-react", "@babel/preset-stage-0"]`
   */


  getMatchingDevDependencies(options = {}) {
    const includes = options.includes || [];
    const excludes = new Set(options.excludes || []);
    return Object.keys(this.metadata.devDependencies).filter(name => !excludes.has(name) && includes.some(prefix => name.startsWith(prefix)));
  }

  async configure(entry) {
    // noinspection SpellCheckingInspection
    this._configuration = {
      context: this.projectDir,
      devtool: this.isProduction || this.isTest ? "nosources-source-map" : "eval-source-map",
      externals: this.computeExternals(),
      node: {
        __dirname: !this.isProduction,
        __filename: !this.isProduction
      },
      output: {
        filename: "[name].js",
        chunkFilename: "[name].bundle.js",
        libraryTarget: "commonjs2",
        path: path.join(this.commonDistDirectory, this.type)
      },
      target: this.isTest ? "node" : `electron-${this.type === "renderer-dll" ? "renderer" : this.type}`,
      resolve: {
        alias: {
          "@": this.sourceDir,
          common: this.commonSourceDirectory
        },
        extensions: this.extensions
      },
      module: {
        rules: this.rules
      },
      plugins: this.plugins
    };

    if (entry != null) {
      this._configuration.entry = entry;
    } // if electronVersion not specified, use latest


    this._electronVersion = this.electronWebpackConfiguration.electronVersion || (await this.electronVersionPromise.value) || "3.0.7";

    const target = (() => {
      switch (this.type) {
        case "renderer":
          return new (_RendererTarget().RendererTarget)();

        case "renderer-dll":
          return new (_RendererTarget().BaseRendererTarget)();

        case "test":
          return new (_RendererTarget().BaseRendererTarget)();

        case "main":
          return new (_MainTarget().MainTarget)();

        default:
          return new (_BaseTarget().BaseTarget)();
      }
    })();

    this.debug(`Target class: ${target.constructor.name}`);
    target.configureRules(this);
    await Promise.all([target.configurePlugins(this), (0, _ts().configureTypescript)(this)]);
    (0, _vue().configureVue)(this);

    if (this.debug.enabled) {
      this.debug(`\n\n${this.type} config:` + JSON.stringify(this._configuration, null, 2) + "\n\n");
    }

    if (this.config.entry == null) {
      this.entryFiles.push((await computeEntryFile(this.sourceDir, this.projectDir)));
      this.config.entry = {
        [this.type]: this.entryFiles
      };
      const mainConfiguration = this.electronWebpackConfiguration.main || {};
      let extraEntries = mainConfiguration.extraEntries;

      if (this.type === "main" && extraEntries != null) {
        if (typeof extraEntries === "string") {
          extraEntries = [extraEntries];
        }

        if (Array.isArray(extraEntries)) {
          for (const p of extraEntries) {
            this.config.entry[path.basename(p, path.extname(p))] = p;
          }
        } else {
          Object.assign(this.config.entry, extraEntries);
        }
      }
    } // noinspection ES6RedundantAwait


    this._configuration = await Promise.resolve(this.applyCustomModifications(this.config));
    return this.config;
  }

  applyCustomModifications(config) {
    const {
      renderer,
      main
    } = this.electronWebpackConfiguration;

    const applyCustom = configPath => {
      const customModule = require(path.join(this.projectDir, configPath));

      if (typeof customModule === "function") {
        return customModule(config, this);
      } else {
        return _webpackMerge().default.smart(config, customModule);
      }
    };

    if (this.type === "renderer" && renderer && renderer.webpackConfig) {
      return applyCustom(renderer.webpackConfig);
    } else if (this.type === "renderer-dll" && renderer && renderer.webpackDllConfig) {
      return applyCustom(renderer.webpackDllConfig);
    } else if (this.type === "main" && main && main.webpackConfig) {
      return applyCustom(main.webpackConfig);
    } else {
      return config;
    }
  }

  computeExternals() {
    const whiteListedModules = new Set(this.electronWebpackConfiguration.whiteListedModules || []);

    if (this.isRenderer) {
      whiteListedModules.add("react");
      whiteListedModules.add("react-dom");
      whiteListedModules.add("vue");
    }

    const filter = name => !name.startsWith("@types/") && (whiteListedModules == null || !whiteListedModules.has(name));

    const externals = Object.keys(this.metadata.dependencies).filter(filter);
    externals.push("electron");
    externals.push("webpack"); // because electron-devtools-installer specified in the devDependencies, but required in the index.dev

    externals.push("electron-devtools-installer");

    if (this.type === "main") {
      externals.push("webpack/hot/log-apply-result");
      externals.push("electron-webpack/out/electron-main-hmr/HmrClient");
      externals.push("source-map-support/source-map-support.js");
    }

    if (this.electronWebpackConfiguration.externals != null) {
      return externals.concat(this.electronWebpackConfiguration.externals);
    }

    return externals;
  }

}

exports.WebpackConfigurator = WebpackConfigurator;
const schemeDataPromise = new (_lazyVal().Lazy)(() => (0, _fsExtra().readJson)(path.join(__dirname, "..", "scheme.json")));

async function createConfigurator(type, env) {
  if (env != null) {
    // allow to pass as `--env.autoClean=false` webpack arg
    const _env = env;

    for (const name of ["minify", "autoClean", "production"]) {
      if (_env[name] === "true") {
        _env[name] = true;
      } else if (_env[name] === "false") {
        _env[name] = false;
      }
    }
  }

  if (env == null) {
    env = {};
  }

  const projectDir = (env.configuration || {}).projectDir || process.cwd();
  const packageMetadata = (0, _config().getPackageMetadata)(projectDir);
  const electronWebpackConfig = await (0, _config().getElectronWebpackConfiguration)({
    packageMetadata,
    projectDir
  });

  if (env.configuration != null) {
    (0, _deepAssign().deepAssign)(electronWebpackConfig, env.configuration);
  }

  await (0, _readConfigFile().validateConfig)(electronWebpackConfig, schemeDataPromise, message => {
    return `${message}

How to fix:
1. Open https://webpack.electron.build/configuration
2. Search the option name on the page.
  * Not found? The option was deprecated or not exists (check spelling).
  * Found? Check that the option in the appropriate place. e.g. "sourceDirectory" only in the "main" or "renderer", not in the root.
`;
  });
  return new WebpackConfigurator(type, env, electronWebpackConfig, (await packageMetadata.value));
}

async function configure(type, env) {
  const configurator = await createConfigurator(type, env);
  const sourceDir = configurator.sourceDir; // explicitly set to null - do not handle at all and do not show info message

  if (sourceDir === null) {
    return null;
  }

  const processEnv = configurator.isProduction ? "production" : "development";
  const dotEnvPath = path.resolve(configurator.projectDir, ".env");
  const dotenvFiles = [`${dotEnvPath}.${processEnv}.local`, `${dotEnvPath}.${processEnv}`, `${dotEnvPath}.local`, dotEnvPath];

  for (const file of dotenvFiles) {
    const exists = await (0, _fsExtra().pathExists)(file);

    if (exists) {
      (0, _dotenvExpand().default)((0, _dotenv().config)({
        path: file
      }));
    }
  }

  return await configurator.configure();
}

async function computeEntryFile(srcDir, projectDir) {
  const candidates = [];

  for (const ext of ["ts", "js", "tsx", "jsx"]) {
    for (const name of ["index", "main", "app"]) {
      candidates.push(`${name}.${ext}`);
    }
  }

  const file = await (0, _util().getFirstExistingFile)(candidates, srcDir);

  if (file == null) {
    throw new Error(`Cannot find entry file ${path.relative(projectDir, path.join(srcDir, "index.ts"))} (or main.ts, or app.ts, or index.js, or main.js, or app.js)`);
  }

  return file;
}

async function getInstalledElectronVersion(projectDir) {
  for (const name of ["electron", "electron-prebuilt", "electron-prebuilt-compile"]) {
    try {
      return (await (0, _fsExtra().readJson)(path.join(projectDir, "node_modules", name, "package.json"))).version;
    } catch (e) {
      if (e.code !== "ENOENT") {
        throw e;
      }
    }
  }
} 
// __ts-babel@6.0.4
//# sourceMappingURL=main.js.map