CasperSecurity

Current Path : /var/www/hrms.uiet.co.in/node_modules/webpack-cli/lib/
Upload File :
Current File : /var/www/hrms.uiet.co.in/node_modules/webpack-cli/lib/webpack-cli.js

const fs = require("fs");
const path = require("path");
const { pathToFileURL } = require("url");
const util = require("util");

const { program, Option } = require("commander");

const WEBPACK_PACKAGE = process.env.WEBPACK_PACKAGE || "webpack";
const WEBPACK_DEV_SERVER_PACKAGE = process.env.WEBPACK_DEV_SERVER_PACKAGE || "webpack-dev-server";

class WebpackCLI {
  constructor() {
    this.colors = this.createColors();
    this.logger = this.getLogger();

    // Initialize program
    this.program = program;
    this.program.name("webpack");
    this.program.configureOutput({
      writeErr: this.logger.error,
      outputError: (str, write) =>
        write(`Error: ${this.capitalizeFirstLetter(str.replace(/^error:/, "").trim())}`),
    });
  }

  capitalizeFirstLetter(str) {
    if (typeof str !== "string") {
      return "";
    }

    return str.charAt(0).toUpperCase() + str.slice(1);
  }

  toKebabCase(str) {
    return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
  }

  createColors(useColor) {
    const { createColors, isColorSupported } = require("colorette");

    let shouldUseColor;

    if (useColor) {
      shouldUseColor = useColor;
    } else {
      shouldUseColor = isColorSupported;
    }

    return { ...createColors({ useColor: shouldUseColor }), isColorSupported: shouldUseColor };
  }

  getLogger() {
    return {
      error: (val) => console.error(`[webpack-cli] ${this.colors.red(util.format(val))}`),
      warn: (val) => console.warn(`[webpack-cli] ${this.colors.yellow(val)}`),
      info: (val) => console.info(`[webpack-cli] ${this.colors.cyan(val)}`),
      success: (val) => console.log(`[webpack-cli] ${this.colors.green(val)}`),
      log: (val) => console.log(`[webpack-cli] ${val}`),
      raw: (val) => console.log(val),
    };
  }

  checkPackageExists(packageName) {
    if (process.versions.pnp) {
      return true;
    }

    let dir = __dirname;

    do {
      try {
        if (fs.statSync(path.join(dir, "node_modules", packageName)).isDirectory()) {
          return true;
        }
      } catch (_error) {
        // Nothing
      }
    } while (dir !== (dir = path.dirname(dir)));

    return false;
  }

  getAvailablePackageManagers() {
    const { sync } = require("execa");
    const installers = ["npm", "yarn", "pnpm"];
    const hasPackageManagerInstalled = (packageManager) => {
      try {
        sync(packageManager, ["--version"]);

        return packageManager;
      } catch (err) {
        return false;
      }
    };
    const availableInstallers = installers.filter((installer) =>
      hasPackageManagerInstalled(installer),
    );

    if (!availableInstallers.length) {
      this.logger.error("No package manager found.");

      process.exit(2);
    }

    return availableInstallers;
  }

  getDefaultPackageManager() {
    const { sync } = require("execa");
    const hasLocalNpm = fs.existsSync(path.resolve(process.cwd(), "package-lock.json"));

    if (hasLocalNpm) {
      return "npm";
    }

    const hasLocalYarn = fs.existsSync(path.resolve(process.cwd(), "yarn.lock"));

    if (hasLocalYarn) {
      return "yarn";
    }

    const hasLocalPnpm = fs.existsSync(path.resolve(process.cwd(), "pnpm-lock.yaml"));

    if (hasLocalPnpm) {
      return "pnpm";
    }

    try {
      // the sync function below will fail if npm is not installed,
      // an error will be thrown
      if (sync("npm", ["--version"])) {
        return "npm";
      }
    } catch (e) {
      // Nothing
    }

    try {
      // the sync function below will fail if yarn is not installed,
      // an error will be thrown
      if (sync("yarn", ["--version"])) {
        return "yarn";
      }
    } catch (e) {
      // Nothing
    }

    try {
      // the sync function below will fail if pnpm is not installed,
      // an error will be thrown
      if (sync("pnpm", ["--version"])) {
        return "pnpm";
      }
    } catch (e) {
      this.logger.error("No package manager found.");

      process.exit(2);
    }
  }

  async doInstall(packageName, options = {}) {
    const packageManager = this.getDefaultPackageManager();

    if (!packageManager) {
      this.logger.error("Can't find package manager");

      process.exit(2);
    }

    if (options.preMessage) {
      options.preMessage();
    }

    // yarn uses 'add' command, rest npm and pnpm both use 'install'
    const commandToBeRun = `${packageManager} ${[
      packageManager === "yarn" ? "add" : "install",
      "-D",
      packageName,
    ].join(" ")}`;

    const prompt = ({ message, defaultResponse, stream }) => {
      const readline = require("readline");
      const rl = readline.createInterface({
        input: process.stdin,
        output: stream,
      });

      return new Promise((resolve) => {
        rl.question(`${message} `, (answer) => {
          // Close the stream
          rl.close();

          const response = (answer || defaultResponse).toLowerCase();

          // Resolve with the input response
          if (response === "y" || response === "yes") {
            resolve(true);
          } else {
            resolve(false);
          }
        });
      });
    };

    let needInstall;

    try {
      needInstall = await prompt({
        message: `[webpack-cli] Would you like to install '${this.colors.green(
          packageName,
        )}' package? (That will run '${this.colors.green(commandToBeRun)}') (${this.colors.yellow(
          "Y/n",
        )})`,
        defaultResponse: "Y",
        stream: process.stderr,
      });
    } catch (error) {
      this.logger.error(error);

      process.exit(error);
    }

    if (needInstall) {
      const execa = require("execa");

      try {
        await execa(commandToBeRun, [], { stdio: "inherit", shell: true });
      } catch (error) {
        this.logger.error(error);

        process.exit(2);
      }

      return packageName;
    }

    process.exit(2);
  }

  async tryRequireThenImport(module, handleError = true) {
    let result;

    try {
      result = require(module);
    } catch (error) {
      const dynamicImportLoader = require("./utils/dynamic-import-loader")();
      if (
        (error.code === "ERR_REQUIRE_ESM" || process.env.WEBPACK_CLI_FORCE_LOAD_ESM_CONFIG) &&
        pathToFileURL &&
        dynamicImportLoader
      ) {
        const urlForConfig = pathToFileURL(module);

        result = await dynamicImportLoader(urlForConfig);
        result = result.default;

        return result;
      }

      if (handleError) {
        this.logger.error(error);
        process.exit(2);
      } else {
        throw error;
      }
    }

    // For babel/typescript
    if (result && typeof result === "object" && "default" in result) {
      result = result.default || {};
    }

    return result || {};
  }

  loadJSONFile(pathToFile, handleError = true) {
    let result;

    try {
      result = require(pathToFile);
    } catch (error) {
      if (handleError) {
        this.logger.error(error);
        process.exit(2);
      } else {
        throw error;
      }
    }

    return result;
  }

  async makeCommand(commandOptions, options, action) {
    const alreadyLoaded = this.program.commands.find(
      (command) =>
        command.name() === commandOptions.name.split(" ")[0] ||
        command.aliases().includes(commandOptions.alias),
    );

    if (alreadyLoaded) {
      return;
    }

    const command = this.program.command(commandOptions.name, {
      noHelp: commandOptions.noHelp,
      hidden: commandOptions.hidden,
      isDefault: commandOptions.isDefault,
    });

    if (commandOptions.description) {
      command.description(commandOptions.description, commandOptions.argsDescription);
    }

    if (commandOptions.usage) {
      command.usage(commandOptions.usage);
    }

    if (Array.isArray(commandOptions.alias)) {
      command.aliases(commandOptions.alias);
    } else {
      command.alias(commandOptions.alias);
    }

    if (commandOptions.pkg) {
      command.pkg = commandOptions.pkg;
    } else {
      command.pkg = "webpack-cli";
    }

    const { forHelp } = this.program;

    let allDependenciesInstalled = true;

    if (commandOptions.dependencies && commandOptions.dependencies.length > 0) {
      for (const dependency of commandOptions.dependencies) {
        const isPkgExist = this.checkPackageExists(dependency);

        if (isPkgExist) {
          continue;
        } else if (!isPkgExist && forHelp) {
          allDependenciesInstalled = false;
          continue;
        }

        let skipInstallation = false;

        // Allow to use `./path/to/webpack.js` outside `node_modules`
        if (dependency === WEBPACK_PACKAGE && fs.existsSync(WEBPACK_PACKAGE)) {
          skipInstallation = true;
        }

        // Allow to use `./path/to/webpack-dev-server.js` outside `node_modules`
        if (dependency === WEBPACK_DEV_SERVER_PACKAGE && fs.existsSync(WEBPACK_PACKAGE)) {
          skipInstallation = true;
        }

        if (skipInstallation) {
          continue;
        }

        await this.doInstall(dependency, {
          preMessage: () => {
            this.logger.error(
              `For using '${this.colors.green(
                commandOptions.name.split(" ")[0],
              )}' command you need to install: '${this.colors.green(dependency)}' package.`,
            );
          },
        });
      }
    }

    if (options) {
      if (typeof options === "function") {
        if (forHelp && !allDependenciesInstalled) {
          command.description(
            `${
              commandOptions.description
            } To see all available options you need to install ${commandOptions.dependencies
              .map((dependency) => `'${dependency}'`)
              .join(", ")}.`,
          );
          options = [];
        } else {
          options = await options();
        }
      }

      options.forEach((optionForCommand) => {
        this.makeOption(command, optionForCommand);
      });
    }

    command.action(action);

    return command;
  }

  makeOption(command, option) {
    let mainOption;
    let negativeOption;

    if (option.configs) {
      let needNegativeOption = false;
      const mainOptionType = new Set();

      option.configs.forEach((config) => {
        // Possible value: "enum" | "string" | "path" | "number" | "boolean" | "RegExp" | "reset"
        switch (config.type) {
          case "reset":
            mainOptionType.add(Boolean);
            break;
          case "boolean":
            if (!needNegativeOption) {
              needNegativeOption = true;
            }

            mainOptionType.add(Boolean);
            break;
          case "number":
            mainOptionType.add(Number);
            break;
          case "string":
          case "path":
          case "RegExp":
            mainOptionType.add(String);
            break;
          case "enum": {
            let hasFalseEnum = false;

            const enumTypes = config.values.map((value) => {
              switch (typeof value) {
                case "string":
                  mainOptionType.add(String);
                  break;
                case "number":
                  mainOptionType.add(Number);
                  break;
                case "boolean":
                  if (!hasFalseEnum && value === false) {
                    hasFalseEnum = true;
                    break;
                  }

                  mainOptionType.add(Boolean);
                  break;
              }
            });

            if (!needNegativeOption) {
              needNegativeOption = hasFalseEnum;
            }

            return enumTypes;
          }
        }
      });

      mainOption = {
        flags: option.alias ? `-${option.alias}, --${option.name}` : `--${option.name}`,
        description: option.description || "",
        type: mainOptionType,
        multiple: option.multiple,
        defaultValue: option.defaultValue,
      };

      if (needNegativeOption) {
        negativeOption = {
          flags: `--no-${option.name}`,
          description: option.negatedDescription
            ? option.negatedDescription
            : `Negative '${option.name}' option.`,
        };
      }
    } else {
      mainOption = {
        flags: option.alias ? `-${option.alias}, --${option.name}` : `--${option.name}`,
        // TODO `describe` used by `webpack-dev-server@3`
        description: option.description || option.describe || "",
        type: option.type
          ? new Set(Array.isArray(option.type) ? option.type : [option.type])
          : new Set([Boolean]),
        multiple: option.multiple,
        defaultValue: option.defaultValue,
      };

      if (option.negative) {
        negativeOption = {
          flags: `--no-${option.name}`,
          description: option.negatedDescription
            ? option.negatedDescription
            : `Negative '${option.name}' option.`,
        };
      }
    }

    if (mainOption.type.size > 1 && mainOption.type.has(Boolean)) {
      mainOption.flags = `${mainOption.flags} [value${mainOption.multiple ? "..." : ""}]`;
    } else if (mainOption.type.size > 0 && !mainOption.type.has(Boolean)) {
      mainOption.flags = `${mainOption.flags} <value${mainOption.multiple ? "..." : ""}>`;
    }

    if (mainOption.type.size === 1) {
      if (mainOption.type.has(Number)) {
        let skipDefault = true;

        const optionForCommand = new Option(mainOption.flags, mainOption.description)
          .argParser((value, prev = []) => {
            if (mainOption.defaultValue && mainOption.multiple && skipDefault) {
              prev = [];
              skipDefault = false;
            }

            return mainOption.multiple ? [].concat(prev).concat(Number(value)) : Number(value);
          })
          .default(mainOption.defaultValue);

        optionForCommand.helpLevel = option.helpLevel;

        command.addOption(optionForCommand);
      } else if (mainOption.type.has(String)) {
        let skipDefault = true;

        const optionForCommand = new Option(mainOption.flags, mainOption.description)
          .argParser((value, prev = []) => {
            if (mainOption.defaultValue && mainOption.multiple && skipDefault) {
              prev = [];
              skipDefault = false;
            }

            return mainOption.multiple ? [].concat(prev).concat(value) : value;
          })
          .default(mainOption.defaultValue);

        optionForCommand.helpLevel = option.helpLevel;

        command.addOption(optionForCommand);
      } else if (mainOption.type.has(Boolean)) {
        const optionForCommand = new Option(mainOption.flags, mainOption.description).default(
          mainOption.defaultValue,
        );

        optionForCommand.helpLevel = option.helpLevel;

        command.addOption(optionForCommand);
      } else {
        const optionForCommand = new Option(mainOption.flags, mainOption.description)
          .argParser(Array.from(mainOption.type)[0])
          .default(mainOption.defaultValue);

        optionForCommand.helpLevel = option.helpLevel;

        command.addOption(optionForCommand);
      }
    } else if (mainOption.type.size > 1) {
      let skipDefault = true;

      const optionForCommand = new Option(
        mainOption.flags,
        mainOption.description,
        mainOption.defaultValue,
      )
        .argParser((value, prev = []) => {
          if (mainOption.defaultValue && mainOption.multiple && skipDefault) {
            prev = [];
            skipDefault = false;
          }

          if (mainOption.type.has(Number)) {
            const numberValue = Number(value);

            if (!isNaN(numberValue)) {
              return mainOption.multiple ? [].concat(prev).concat(numberValue) : numberValue;
            }
          }

          if (mainOption.type.has(String)) {
            return mainOption.multiple ? [].concat(prev).concat(value) : value;
          }

          return value;
        })
        .default(mainOption.defaultValue);

      optionForCommand.helpLevel = option.helpLevel;

      command.addOption(optionForCommand);
    } else if (mainOption.type.size === 0 && negativeOption) {
      const optionForCommand = new Option(mainOption.flags, mainOption.description);

      // Hide stub option
      optionForCommand.hideHelp();
      optionForCommand.helpLevel = option.helpLevel;

      command.addOption(optionForCommand);
    }

    if (negativeOption) {
      const optionForCommand = new Option(negativeOption.flags, negativeOption.description);

      optionForCommand.helpLevel = option.helpLevel;

      command.addOption(optionForCommand);
    }
  }

  getBuiltInOptions() {
    if (this.builtInOptionsCache) {
      return this.builtInOptionsCache;
    }

    const minimumHelpFlags = [
      "config",
      "config-name",
      "merge",
      "env",
      "mode",
      "watch",
      "watch-options-stdin",
      "stats",
      "devtool",
      "entry",
      "target",
      "progress",
      "json",
      "name",
      "output-path",
      "node-env",
    ];

    const builtInFlags = [
      // For configs
      {
        name: "config",
        alias: "c",
        configs: [
          {
            type: "string",
          },
        ],
        multiple: true,
        description: "Provide path to a webpack configuration file e.g. ./webpack.config.js.",
      },
      {
        name: "config-name",
        configs: [
          {
            type: "string",
          },
        ],
        multiple: true,
        description: "Name of the configuration to use.",
      },
      {
        name: "merge",
        alias: "m",
        configs: [
          {
            type: "enum",
            values: [true],
          },
        ],
        description: "Merge two or more configurations using 'webpack-merge'.",
      },
      // Complex configs
      {
        name: "env",
        type: (value, previous = {}) => {
          // for https://github.com/webpack/webpack-cli/issues/2642
          if (value.endsWith("=")) {
            value.concat('""');
          }

          // This ensures we're only splitting by the first `=`
          const [allKeys, val] = value.split(/=(.+)/, 2);
          const splitKeys = allKeys.split(/\.(?!$)/);

          let prevRef = previous;

          splitKeys.forEach((someKey, index) => {
            if (!prevRef[someKey]) {
              prevRef[someKey] = {};
            }

            if (typeof prevRef[someKey] === "string") {
              prevRef[someKey] = {};
            }

            if (index === splitKeys.length - 1) {
              if (typeof val === "string") {
                prevRef[someKey] = val;
              } else {
                prevRef[someKey] = true;
              }
            }

            prevRef = prevRef[someKey];
          });

          return previous;
        },
        multiple: true,
        description: "Environment passed to the configuration when it is a function.",
      },
      {
        name: "node-env",
        configs: [
          {
            type: "string",
          },
        ],
        multiple: false,
        description: "Sets process.env.NODE_ENV to the specified value.",
      },

      // Adding more plugins
      {
        name: "hot",
        alias: "h",
        configs: [
          {
            type: "string",
          },
          {
            type: "boolean",
          },
        ],
        negative: true,
        description: "Enables Hot Module Replacement",
        negatedDescription: "Disables Hot Module Replacement.",
      },
      {
        name: "analyze",
        configs: [
          {
            type: "enum",
            values: [true],
          },
        ],
        multiple: false,
        description: "It invokes webpack-bundle-analyzer plugin to get bundle information.",
      },
      {
        name: "progress",
        configs: [
          {
            type: "string",
          },
          {
            type: "enum",
            values: [true],
          },
        ],
        description: "Print compilation progress during build.",
      },
      {
        name: "prefetch",
        configs: [
          {
            type: "string",
          },
        ],
        description: "Prefetch this request.",
      },

      // Output options
      {
        name: "json",
        configs: [
          {
            type: "string",
          },
          {
            type: "enum",
            values: [true],
          },
        ],
        alias: "j",
        description: "Prints result as JSON or store it in a file.",
      },

      // For webpack@4
      {
        name: "entry",
        configs: [
          {
            type: "string",
          },
        ],
        multiple: true,
        description: "The entry point(s) of your application e.g. ./src/main.js.",
      },
      {
        name: "output-path",
        alias: "o",
        configs: [
          {
            type: "string",
          },
        ],
        description: "Output location of the file generated by webpack e.g. ./dist/.",
      },
      {
        name: "target",
        alias: "t",
        configs: [
          {
            type: "string",
          },
        ],
        multiple: this.webpack.cli !== undefined,
        description: "Sets the build target e.g. node.",
      },
      {
        name: "devtool",
        configs: [
          {
            type: "string",
          },
          {
            type: "enum",
            values: [false],
          },
        ],
        negative: true,
        alias: "d",
        description: "Determine source maps to use.",
        negatedDescription: "Do not generate source maps.",
      },
      {
        name: "mode",
        configs: [
          {
            type: "string",
          },
        ],
        description: "Defines the mode to pass to webpack.",
      },
      {
        name: "name",
        configs: [
          {
            type: "string",
          },
        ],
        description: "Name of the configuration. Used when loading multiple configurations.",
      },
      {
        name: "stats",
        configs: [
          {
            type: "string",
          },
          {
            type: "boolean",
          },
        ],
        negative: true,
        description: "It instructs webpack on how to treat the stats e.g. verbose.",
        negatedDescription: "Disable stats output.",
      },
      {
        name: "watch",
        configs: [
          {
            type: "boolean",
          },
        ],
        negative: true,
        alias: "w",
        description: "Watch for files changes.",
        negatedDescription: "Do not watch for file changes.",
      },
      {
        name: "watch-options-stdin",
        configs: [
          {
            type: "boolean",
          },
        ],
        negative: true,
        description: "Stop watching when stdin stream has ended.",
        negatedDescription: "Do not stop watching when stdin stream has ended.",
      },
    ];

    // Extract all the flags being exported from core.
    // A list of cli flags generated by core can be found here https://github.com/webpack/webpack/blob/master/test/__snapshots__/Cli.test.js.snap
    const coreFlags = this.webpack.cli
      ? Object.entries(this.webpack.cli.getArguments()).map(([flag, meta]) => {
          const inBuiltIn = builtInFlags.find((builtInFlag) => builtInFlag.name === flag);

          if (inBuiltIn) {
            return {
              ...meta,
              name: flag,
              group: "core",
              ...inBuiltIn,
              configs: meta.configs || [],
            };
          }

          return { ...meta, name: flag, group: "core" };
        })
      : [];

    const options = []
      .concat(
        builtInFlags.filter(
          (builtInFlag) => !coreFlags.find((coreFlag) => builtInFlag.name === coreFlag.name),
        ),
      )
      .concat(coreFlags)
      .map((option) => {
        option.helpLevel = minimumHelpFlags.includes(option.name) ? "minimum" : "verbose";

        return option;
      });

    this.builtInOptionsCache = options;

    return options;
  }

  async loadWebpack(handleError = true) {
    return this.tryRequireThenImport(WEBPACK_PACKAGE, handleError);
  }

  async run(args, parseOptions) {
    // Built-in internal commands
    const buildCommandOptions = {
      name: "build [entries...]",
      alias: ["bundle", "b"],
      description: "Run webpack (default command, can be omitted).",
      usage: "[entries...] [options]",
      dependencies: [WEBPACK_PACKAGE],
    };
    const watchCommandOptions = {
      name: "watch [entries...]",
      alias: "w",
      description: "Run webpack and watch for files changes.",
      usage: "[entries...] [options]",
      dependencies: [WEBPACK_PACKAGE],
    };
    const versionCommandOptions = {
      name: "version [commands...]",
      alias: "v",
      description:
        "Output the version number of 'webpack', 'webpack-cli' and 'webpack-dev-server' and commands.",
    };
    const helpCommandOptions = {
      name: "help [command] [option]",
      alias: "h",
      description: "Display help for commands and options.",
    };
    // Built-in external commands
    const externalBuiltInCommandsInfo = [
      {
        name: "serve [entries...]",
        alias: ["server", "s"],
        pkg: "@webpack-cli/serve",
      },
      {
        name: "info",
        alias: "i",
        pkg: "@webpack-cli/info",
      },
      {
        name: "init",
        alias: ["create", "new", "c", "n"],
        pkg: "@webpack-cli/generators",
      },
      {
        name: "loader",
        alias: "l",
        pkg: "@webpack-cli/generators",
      },
      {
        name: "plugin",
        alias: "p",
        pkg: "@webpack-cli/generators",
      },
      {
        name: "migrate",
        alias: "m",
        pkg: "@webpack-cli/migrate",
      },
      {
        name: "configtest [config-path]",
        alias: "t",
        pkg: "@webpack-cli/configtest",
      },
    ];

    const knownCommands = [
      buildCommandOptions,
      watchCommandOptions,
      versionCommandOptions,
      helpCommandOptions,
      ...externalBuiltInCommandsInfo,
    ];
    const getCommandName = (name) => name.split(" ")[0];
    const isKnownCommand = (name) =>
      knownCommands.find(
        (command) =>
          getCommandName(command.name) === name ||
          (Array.isArray(command.alias) ? command.alias.includes(name) : command.alias === name),
      );
    const isCommand = (input, commandOptions) => {
      const longName = getCommandName(commandOptions.name);

      if (input === longName) {
        return true;
      }

      if (commandOptions.alias) {
        if (Array.isArray(commandOptions.alias)) {
          return commandOptions.alias.includes(input);
        } else {
          return commandOptions.alias === input;
        }
      }

      return false;
    };
    const findCommandByName = (name) =>
      this.program.commands.find(
        (command) => name === command.name() || command.aliases().includes(name),
      );
    const isOption = (value) => value.startsWith("-");
    const isGlobalOption = (value) =>
      value === "--color" ||
      value === "--no-color" ||
      value === "-v" ||
      value === "--version" ||
      value === "-h" ||
      value === "--help";

    const loadCommandByName = async (commandName, allowToInstall = false) => {
      const isBuildCommandUsed = isCommand(commandName, buildCommandOptions);
      const isWatchCommandUsed = isCommand(commandName, watchCommandOptions);

      if (isBuildCommandUsed || isWatchCommandUsed) {
        await this.makeCommand(
          isBuildCommandUsed ? buildCommandOptions : watchCommandOptions,
          async () => {
            this.webpack = await this.loadWebpack();

            return isWatchCommandUsed
              ? this.getBuiltInOptions().filter((option) => option.name !== "watch")
              : this.getBuiltInOptions();
          },
          async (entries, options) => {
            if (entries.length > 0) {
              options.entry = [...entries, ...(options.entry || [])];
            }

            await this.runWebpack(options, isWatchCommandUsed);
          },
        );
      } else if (isCommand(commandName, helpCommandOptions)) {
        // Stub for the `help` command
        this.makeCommand(helpCommandOptions, [], () => {});
      } else if (isCommand(commandName, versionCommandOptions)) {
        // Stub for the `version` command
        this.makeCommand(versionCommandOptions, [], () => {});
      } else {
        const builtInExternalCommandInfo = externalBuiltInCommandsInfo.find(
          (externalBuiltInCommandInfo) =>
            getCommandName(externalBuiltInCommandInfo.name) === commandName ||
            (Array.isArray(externalBuiltInCommandInfo.alias)
              ? externalBuiltInCommandInfo.alias.includes(commandName)
              : externalBuiltInCommandInfo.alias === commandName),
        );

        let pkg;

        if (builtInExternalCommandInfo) {
          ({ pkg } = builtInExternalCommandInfo);
        } else {
          pkg = commandName;
        }

        if (pkg !== "webpack-cli" && !this.checkPackageExists(pkg)) {
          if (!allowToInstall) {
            return;
          }

          pkg = await this.doInstall(pkg, {
            preMessage: () => {
              this.logger.error(
                `For using this command you need to install: '${this.colors.green(pkg)}' package.`,
              );
            },
          });
        }

        let loadedCommand;

        try {
          loadedCommand = await this.tryRequireThenImport(pkg, false);
        } catch (error) {
          // Ignore, command is not installed

          return;
        }

        let command;

        try {
          command = new loadedCommand();

          await command.apply(this);
        } catch (error) {
          this.logger.error(`Unable to load '${pkg}' command`);
          this.logger.error(error);
          process.exit(2);
        }
      }
    };

    // Register own exit
    this.program.exitOverride(async (error) => {
      if (error.exitCode === 0) {
        process.exit(0);
      }

      if (error.code === "executeSubCommandAsync") {
        process.exit(2);
      }

      if (error.code === "commander.help") {
        process.exit(0);
      }

      if (error.code === "commander.unknownOption") {
        let name = error.message.match(/'(.+)'/);

        if (name) {
          name = name[1].substr(2);

          if (name.includes("=")) {
            name = name.split("=")[0];
          }

          const { operands } = this.program.parseOptions(this.program.args);
          const operand =
            typeof operands[0] !== "undefined"
              ? operands[0]
              : getCommandName(buildCommandOptions.name);

          if (operand) {
            const command = findCommandByName(operand);

            if (!command) {
              this.logger.error(`Can't find and load command '${operand}'`);
              this.logger.error("Run 'webpack --help' to see available commands and options");
              process.exit(2);
            }

            const levenshtein = require("fastest-levenshtein");

            command.options.forEach((option) => {
              if (!option.hidden && levenshtein.distance(name, option.long.slice(2)) < 3) {
                this.logger.error(`Did you mean '--${option.name()}'?`);
              }
            });
          }
        }
      }

      // Codes:
      // - commander.unknownCommand
      // - commander.missingArgument
      // - commander.missingMandatoryOptionValue
      // - commander.optionMissingArgument

      this.logger.error("Run 'webpack --help' to see available commands and options");
      process.exit(2);
    });

    // Default `--color` and `--no-color` options
    const cli = this;
    this.program.option("--color", "Enable colors on console.");
    this.program.on("option:color", function () {
      const { color } = this.opts();

      cli.isColorSupportChanged = color;
      cli.colors = cli.createColors(color);
    });
    this.program.option("--no-color", "Disable colors on console.");
    this.program.on("option:no-color", function () {
      const { color } = this.opts();

      cli.isColorSupportChanged = color;
      cli.colors = cli.createColors(color);
    });

    // Make `-v, --version` options
    // Make `version|v [commands...]` command
    const outputVersion = async (options) => {
      // Filter `bundle`, `watch`, `version` and `help` commands
      const possibleCommandNames = options.filter(
        (option) =>
          !isCommand(option, buildCommandOptions) &&
          !isCommand(option, watchCommandOptions) &&
          !isCommand(option, versionCommandOptions) &&
          !isCommand(option, helpCommandOptions),
      );

      possibleCommandNames.forEach((possibleCommandName) => {
        if (!isOption(possibleCommandName)) {
          return;
        }

        this.logger.error(`Unknown option '${possibleCommandName}'`);
        this.logger.error("Run 'webpack --help' to see available commands and options");
        process.exit(2);
      });

      if (possibleCommandNames.length > 0) {
        await Promise.all(
          possibleCommandNames.map((possibleCommand) => loadCommandByName(possibleCommand)),
        );

        for (const possibleCommandName of possibleCommandNames) {
          const foundCommand = findCommandByName(possibleCommandName);

          if (!foundCommand) {
            this.logger.error(`Unknown command '${possibleCommandName}'`);
            this.logger.error("Run 'webpack --help' to see available commands and options");
            process.exit(2);
          }

          try {
            const { name, version } = this.loadJSONFile(`${foundCommand.pkg}/package.json`);

            this.logger.raw(`${name} ${version}`);
          } catch (e) {
            this.logger.error(`Error: External package '${foundCommand.pkg}' not found`);
            process.exit(2);
          }
        }
      }

      let webpack;

      try {
        webpack = await this.loadWebpack(false);
      } catch (_error) {
        // Nothing
      }

      this.logger.raw(`webpack: ${webpack ? webpack.version : "not installed"}`);

      const pkgJSON = this.loadJSONFile("../package.json");

      this.logger.raw(`webpack-cli: ${pkgJSON.version}`);

      let devServer;

      try {
        devServer = await this.loadJSONFile("webpack-dev-server/package.json", false);
      } catch (_error) {
        // Nothing
      }

      this.logger.raw(`webpack-dev-server ${devServer ? devServer.version : "not installed"}`);

      process.exit(0);
    };
    this.program.option(
      "-v, --version",
      "Output the version number of 'webpack', 'webpack-cli' and 'webpack-dev-server' and commands.",
    );

    const outputHelp = async (options, isVerbose, isHelpCommandSyntax, program) => {
      const { bold } = this.colors;
      const outputIncorrectUsageOfHelp = () => {
        this.logger.error("Incorrect use of help");
        this.logger.error(
          "Please use: 'webpack help [command] [option]' | 'webpack [command] --help'",
        );
        this.logger.error("Run 'webpack --help' to see available commands and options");
        process.exit(2);
      };

      const isGlobalHelp = options.length === 0;
      const isCommandHelp = options.length === 1 && !isOption(options[0]);

      if (isGlobalHelp || isCommandHelp) {
        program.configureHelp({
          sortSubcommands: true,
          // Support multiple aliases
          commandUsage: (command) => {
            let parentCmdNames = "";

            for (let parentCmd = command.parent; parentCmd; parentCmd = parentCmd.parent) {
              parentCmdNames = `${parentCmd.name()} ${parentCmdNames}`;
            }

            if (isGlobalHelp) {
              return `${parentCmdNames}${command.usage()}\n${bold(
                "Alternative usage to run commands:",
              )} ${parentCmdNames}[command] [options]`;
            }

            return `${parentCmdNames}${command.name()}|${command
              .aliases()
              .join("|")} ${command.usage()}`;
          },
          // Support multiple aliases
          subcommandTerm: (command) => {
            const humanReadableArgumentName = (argument) => {
              const nameOutput = argument.name + (argument.variadic === true ? "..." : "");

              return argument.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
            };
            const args = command._args.map((arg) => humanReadableArgumentName(arg)).join(" ");

            return `${command.name()}|${command.aliases().join("|")}${args ? ` ${args}` : ""}${
              command.options.length > 0 ? " [options]" : ""
            }`;
          },
          visibleOptions: function visibleOptions(command) {
            return command.options.filter((option) => {
              if (option.hidden) {
                return false;
              }

              switch (option.helpLevel) {
                case "verbose":
                  return isVerbose;
                case "minimum":
                default:
                  return true;
              }
            });
          },
          padWidth(command, helper) {
            return Math.max(
              helper.longestArgumentTermLength(command, helper),
              helper.longestOptionTermLength(command, helper),
              // For global options
              helper.longestOptionTermLength(program, helper),
              helper.longestSubcommandTermLength(isGlobalHelp ? program : command, helper),
            );
          },
          formatHelp: (command, helper) => {
            const termWidth = helper.padWidth(command, helper);
            const helpWidth = helper.helpWidth || process.env.WEBPACK_CLI_HELP_WIDTH || 80;
            const itemIndentWidth = 2;
            const itemSeparatorWidth = 2; // between term and description

            const formatItem = (term, description) => {
              if (description) {
                const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;

                return helper.wrap(
                  fullText,
                  helpWidth - itemIndentWidth,
                  termWidth + itemSeparatorWidth,
                );
              }

              return term;
            };

            const formatList = (textArray) =>
              textArray.join("\n").replace(/^/gm, " ".repeat(itemIndentWidth));

            // Usage
            let output = [`${bold("Usage:")} ${helper.commandUsage(command)}`, ""];

            // Description
            const commandDescription = isGlobalHelp
              ? "The build tool for modern web applications."
              : helper.commandDescription(command);

            if (commandDescription.length > 0) {
              output = output.concat([commandDescription, ""]);
            }

            // Arguments
            const argumentList = helper
              .visibleArguments(command)
              .map((argument) => formatItem(argument.term, argument.description));

            if (argumentList.length > 0) {
              output = output.concat([bold("Arguments:"), formatList(argumentList), ""]);
            }

            // Options
            const optionList = helper
              .visibleOptions(command)
              .map((option) =>
                formatItem(helper.optionTerm(option), helper.optionDescription(option)),
              );

            if (optionList.length > 0) {
              output = output.concat([bold("Options:"), formatList(optionList), ""]);
            }

            // Global options
            const globalOptionList = program.options.map((option) =>
              formatItem(helper.optionTerm(option), helper.optionDescription(option)),
            );

            if (globalOptionList.length > 0) {
              output = output.concat([bold("Global options:"), formatList(globalOptionList), ""]);
            }

            // Commands
            const commandList = helper
              .visibleCommands(isGlobalHelp ? program : command)
              .map((command) =>
                formatItem(helper.subcommandTerm(command), helper.subcommandDescription(command)),
              );

            if (commandList.length > 0) {
              output = output.concat([bold("Commands:"), formatList(commandList), ""]);
            }

            return output.join("\n");
          },
        });

        if (isGlobalHelp) {
          await Promise.all(
            knownCommands.map((knownCommand) => {
              return loadCommandByName(getCommandName(knownCommand.name));
            }),
          );

          const buildCommand = findCommandByName(getCommandName(buildCommandOptions.name));

          this.logger.raw(buildCommand.helpInformation());
        } else {
          const name = options[0];

          await loadCommandByName(name);

          const command = findCommandByName(name);

          if (!command) {
            const builtInCommandUsed = externalBuiltInCommandsInfo.find(
              (command) => command.name.includes(name) || name === command.alias,
            );
            if (typeof builtInCommandUsed !== "undefined") {
              this.logger.error(
                `For using '${name}' command you need to install '${builtInCommandUsed.pkg}' package.`,
              );
            } else {
              this.logger.error(`Can't find and load command '${name}'`);
              this.logger.error("Run 'webpack --help' to see available commands and options.");
            }
            process.exit(2);
          }

          this.logger.raw(command.helpInformation());
        }
      } else if (isHelpCommandSyntax) {
        let isCommandSpecified = false;
        let commandName = getCommandName(buildCommandOptions.name);
        let optionName;

        if (options.length === 1) {
          optionName = options[0];
        } else if (options.length === 2) {
          isCommandSpecified = true;
          commandName = options[0];
          optionName = options[1];

          if (isOption(commandName)) {
            outputIncorrectUsageOfHelp();
          }
        } else {
          outputIncorrectUsageOfHelp();
        }

        await loadCommandByName(commandName);

        const command = isGlobalOption(optionName) ? program : findCommandByName(commandName);

        if (!command) {
          this.logger.error(`Can't find and load command '${commandName}'`);
          this.logger.error("Run 'webpack --help' to see available commands and options");
          process.exit(2);
        }

        const option = command.options.find(
          (option) => option.short === optionName || option.long === optionName,
        );

        if (!option) {
          this.logger.error(`Unknown option '${optionName}'`);
          this.logger.error("Run 'webpack --help' to see available commands and options");
          process.exit(2);
        }

        const nameOutput =
          option.flags.replace(/^.+[[<]/, "").replace(/(\.\.\.)?[\]>].*$/, "") +
          (option.variadic === true ? "..." : "");
        const value = option.required
          ? "<" + nameOutput + ">"
          : option.optional
          ? "[" + nameOutput + "]"
          : "";

        this.logger.raw(
          `${bold("Usage")}: webpack${isCommandSpecified ? ` ${commandName}` : ""} ${option.long}${
            value ? ` ${value}` : ""
          }`,
        );

        if (option.short) {
          this.logger.raw(
            `${bold("Short:")} webpack${isCommandSpecified ? ` ${commandName}` : ""} ${
              option.short
            }${value ? ` ${value}` : ""}`,
          );
        }

        if (option.description) {
          this.logger.raw(`${bold("Description:")} ${option.description}`);
        }

        if (!option.negate && option.defaultValue) {
          this.logger.raw(`${bold("Default value:")} ${JSON.stringify(option.defaultValue)}`);
        }

        const flag = this.getBuiltInOptions().find((flag) => option.long === `--${flag.name}`);

        if (flag && flag.configs) {
          const possibleValues = flag.configs.reduce((accumulator, currentValue) => {
            if (currentValue.values) {
              return accumulator.concat(currentValue.values);
            } else {
              return accumulator;
            }
          }, []);

          if (possibleValues.length > 0) {
            this.logger.raw(
              `${bold("Possible values:")} ${JSON.stringify(possibleValues.join(" | "))}`,
            );
          }
        }

        this.logger.raw("");

        // TODO implement this after refactor cli arguments
        // logger.raw('Documentation: https://webpack.js.org/option/name/');
      } else {
        outputIncorrectUsageOfHelp();
      }

      this.logger.raw(
        "To see list of all supported commands and options run 'webpack --help=verbose'.\n",
      );
      this.logger.raw(`${bold("Webpack documentation:")} https://webpack.js.org/.`);
      this.logger.raw(`${bold("CLI documentation:")} https://webpack.js.org/api/cli/.`);
      this.logger.raw(`${bold("Made with ♥ by the webpack team")}.`);
      process.exit(0);
    };
    this.program.helpOption(false);
    this.program.addHelpCommand(false);
    this.program.option("-h, --help [verbose]", "Display help for commands and options.");

    let isInternalActionCalled = false;

    // Default action
    this.program.usage("[options]");
    this.program.allowUnknownOption(true);
    this.program.action(async (options, program) => {
      if (!isInternalActionCalled) {
        isInternalActionCalled = true;
      } else {
        this.logger.error("No commands found to run");
        process.exit(2);
      }

      // Command and options
      const { operands, unknown } = this.program.parseOptions(program.args);
      const defaultCommandToRun = getCommandName(buildCommandOptions.name);
      const hasOperand = typeof operands[0] !== "undefined";
      const operand = hasOperand ? operands[0] : defaultCommandToRun;
      const isHelpOption = typeof options.help !== "undefined";
      const isHelpCommandSyntax = isCommand(operand, helpCommandOptions);

      if (isHelpOption || isHelpCommandSyntax) {
        let isVerbose = false;

        if (isHelpOption) {
          if (typeof options.help === "string") {
            if (options.help !== "verbose") {
              this.logger.error("Unknown value for '--help' option, please use '--help=verbose'");
              process.exit(2);
            }

            isVerbose = true;
          }
        }

        this.program.forHelp = true;

        const optionsForHelp = []
          .concat(isHelpOption && hasOperand ? [operand] : [])
          // Syntax `webpack help [command]`
          .concat(operands.slice(1))
          // Syntax `webpack help [option]`
          .concat(unknown)
          .concat(
            isHelpCommandSyntax && typeof options.color !== "undefined"
              ? [options.color ? "--color" : "--no-color"]
              : [],
          )
          .concat(
            isHelpCommandSyntax && typeof options.version !== "undefined" ? ["--version"] : [],
          );

        await outputHelp(optionsForHelp, isVerbose, isHelpCommandSyntax, program);
      }

      const isVersionOption = typeof options.version !== "undefined";
      const isVersionCommandSyntax = isCommand(operand, versionCommandOptions);

      if (isVersionOption || isVersionCommandSyntax) {
        const optionsForVersion = []
          .concat(isVersionOption ? [operand] : [])
          .concat(operands.slice(1))
          .concat(unknown);

        await outputVersion(optionsForVersion, program);
      }

      let commandToRun = operand;
      let commandOperands = operands.slice(1);

      if (isKnownCommand(commandToRun)) {
        await loadCommandByName(commandToRun, true);
      } else {
        const isEntrySyntax = fs.existsSync(operand);

        if (isEntrySyntax) {
          commandToRun = defaultCommandToRun;
          commandOperands = operands;

          await loadCommandByName(commandToRun);
        } else {
          this.logger.error(`Unknown command or entry '${operand}'`);

          const levenshtein = require("fastest-levenshtein");
          const found = knownCommands.find(
            (commandOptions) =>
              levenshtein.distance(operand, getCommandName(commandOptions.name)) < 3,
          );

          if (found) {
            this.logger.error(
              `Did you mean '${getCommandName(found.name)}' (alias '${
                Array.isArray(found.alias) ? found.alias.join(", ") : found.alias
              }')?`,
            );
          }

          this.logger.error("Run 'webpack --help' to see available commands and options");
          process.exit(2);
        }
      }

      await this.program.parseAsync([commandToRun, ...commandOperands, ...unknown], {
        from: "user",
      });
    });

    await this.program.parseAsync(args, parseOptions);
  }

  async loadConfig(options) {
    const interpret = require("interpret");
    const loadConfigByPath = async (configPath, argv = {}) => {
      const ext = path.extname(configPath);
      const interpreted = Object.keys(interpret.jsVariants).find((variant) => variant === ext);

      if (interpreted) {
        const rechoir = require("rechoir");

        try {
          rechoir.prepare(interpret.extensions, configPath);
        } catch (error) {
          if (error.failures) {
            this.logger.error(`Unable load '${configPath}'`);
            this.logger.error(error.message);
            error.failures.forEach((failure) => {
              this.logger.error(failure.error.message);
            });
            this.logger.error("Please install one of them");
            process.exit(2);
          }

          this.logger.error(error);
          process.exit(2);
        }
      }

      let options;

      try {
        options = await this.tryRequireThenImport(configPath, false);
      } catch (error) {
        this.logger.error(`Failed to load '${configPath}' config`);

        if (this.isValidationError(error)) {
          this.logger.error(error.message);
        } else {
          this.logger.error(error);
        }

        process.exit(2);
      }

      if (Array.isArray(options)) {
        await Promise.all(
          options.map(async (_, i) => {
            if (typeof options[i].then === "function") {
              options[i] = await options[i];
            }

            // `Promise` may return `Function`
            if (typeof options[i] === "function") {
              // when config is a function, pass the env from args to the config function
              options[i] = await options[i](argv.env, argv);
            }
          }),
        );
      } else {
        if (typeof options.then === "function") {
          options = await options;
        }

        // `Promise` may return `Function`
        if (typeof options === "function") {
          // when config is a function, pass the env from args to the config function
          options = await options(argv.env, argv);
        }
      }

      const isObject = (value) => typeof value === "object" && value !== null;

      if (!isObject(options) && !Array.isArray(options)) {
        this.logger.error(`Invalid configuration in '${configPath}'`);

        process.exit(2);
      }

      return { options, path: configPath };
    };

    const config = { options: {}, path: new WeakMap() };

    if (options.config && options.config.length > 0) {
      const loadedConfigs = await Promise.all(
        options.config.map((configPath) =>
          loadConfigByPath(path.resolve(configPath), options.argv),
        ),
      );

      config.options = [];

      loadedConfigs.forEach((loadedConfig) => {
        const isArray = Array.isArray(loadedConfig.options);

        // TODO we should run webpack multiple times when the `--config` options have multiple values with `--merge`, need to solve for the next major release
        if (config.options.length === 0) {
          config.options = loadedConfig.options;
        } else {
          if (!Array.isArray(config.options)) {
            config.options = [config.options];
          }

          if (isArray) {
            loadedConfig.options.forEach((item) => {
              config.options.push(item);
            });
          } else {
            config.options.push(loadedConfig.options);
          }
        }

        if (isArray) {
          loadedConfig.options.forEach((options) => {
            config.path.set(options, loadedConfig.path);
          });
        } else {
          config.path.set(loadedConfig.options, loadedConfig.path);
        }
      });

      config.options = config.options.length === 1 ? config.options[0] : config.options;
    } else {
      // Order defines the priority, in decreasing order
      const defaultConfigFiles = [
        "webpack.config",
        ".webpack/webpack.config",
        ".webpack/webpackfile",
      ]
        .map((filename) =>
          // Since .cjs is not available on interpret side add it manually to default config extension list
          [...Object.keys(interpret.extensions), ".cjs"].map((ext) => ({
            path: path.resolve(filename + ext),
            ext: ext,
            module: interpret.extensions[ext],
          })),
        )
        .reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);

      let foundDefaultConfigFile;

      for (const defaultConfigFile of defaultConfigFiles) {
        if (!fs.existsSync(defaultConfigFile.path)) {
          continue;
        }

        foundDefaultConfigFile = defaultConfigFile;
        break;
      }

      if (foundDefaultConfigFile) {
        const loadedConfig = await loadConfigByPath(foundDefaultConfigFile.path, options.argv);

        config.options = loadedConfig.options;

        if (Array.isArray(config.options)) {
          config.options.forEach((item) => {
            config.path.set(item, loadedConfig.path);
          });
        } else {
          config.path.set(loadedConfig.options, loadedConfig.path);
        }
      }
    }

    if (options.configName) {
      const notFoundConfigNames = [];

      config.options = options.configName.map((configName) => {
        let found;

        if (Array.isArray(config.options)) {
          found = config.options.find((options) => options.name === configName);
        } else {
          found = config.options.name === configName ? config.options : undefined;
        }

        if (!found) {
          notFoundConfigNames.push(configName);
        }

        return found;
      });

      if (notFoundConfigNames.length > 0) {
        this.logger.error(
          notFoundConfigNames
            .map((configName) => `Configuration with the name "${configName}" was not found.`)
            .join(" "),
        );
        process.exit(2);
      }
    }

    if (options.merge) {
      const merge = await this.tryRequireThenImport("webpack-merge");

      // we can only merge when there are multiple configurations
      // either by passing multiple configs by flags or passing a
      // single config exporting an array
      if (!Array.isArray(config.options) || config.options.length <= 1) {
        this.logger.error("At least two configurations are required for merge.");
        process.exit(2);
      }

      const mergedConfigPaths = [];

      config.options = config.options.reduce((accumulator, options) => {
        const configPath = config.path.get(options);
        const mergedOptions = merge(accumulator, options);

        mergedConfigPaths.push(configPath);

        return mergedOptions;
      }, {});
      config.path.set(config.options, mergedConfigPaths);
    }

    return config;
  }

  async buildConfig(config, options) {
    const runFunctionOnEachConfig = (options, fn) => {
      if (Array.isArray(options)) {
        for (let item of options) {
          item = fn(item);
        }
      } else {
        options = fn(options);
      }

      return options;
    };

    if (options.analyze) {
      if (!this.checkPackageExists("webpack-bundle-analyzer")) {
        await this.doInstall("webpack-bundle-analyzer", {
          preMessage: () => {
            this.logger.error(
              `It looks like ${this.colors.yellow("webpack-bundle-analyzer")} is not installed.`,
            );
          },
        });

        this.logger.success(
          `${this.colors.yellow("webpack-bundle-analyzer")} was installed successfully.`,
        );
      }
    }

    if (typeof options.progress === "string" && options.progress !== "profile") {
      this.logger.error(
        `'${options.progress}' is an invalid value for the --progress option. Only 'profile' is allowed.`,
      );
      process.exit(2);
    }

    if (typeof options.hot === "string" && options.hot !== "only") {
      this.logger.error(
        `'${options.hot}' is an invalid value for the --hot option. Use 'only' instead.`,
      );
      process.exit(2);
    }

    const CLIPlugin = await this.tryRequireThenImport("./plugins/CLIPlugin");

    const internalBuildConfig = (item) => {
      // Output warnings
      if (
        item.watch &&
        options.argv &&
        options.argv.env &&
        (options.argv.env["WEBPACK_WATCH"] || options.argv.env["WEBPACK_SERVE"])
      ) {
        this.logger.warn(
          `No need to use the '${
            options.argv.env["WEBPACK_WATCH"] ? "watch" : "serve"
          }' command together with '{ watch: true }' configuration, it does not make sense.`,
        );

        if (options.argv.env["WEBPACK_SERVE"]) {
          item.watch = false;
        }
      }

      // Apply options
      if (this.webpack.cli) {
        const args = this.getBuiltInOptions()
          .filter((flag) => flag.group === "core")
          .reduce((accumulator, flag) => {
            accumulator[flag.name] = flag;

            return accumulator;
          }, {});

        const values = Object.keys(options).reduce((accumulator, name) => {
          if (name === "argv") {
            return accumulator;
          }

          const kebabName = this.toKebabCase(name);

          if (args[kebabName]) {
            accumulator[kebabName] = options[name];
          }

          return accumulator;
        }, {});

        const problems = this.webpack.cli.processArguments(args, item, values);

        if (problems) {
          const groupBy = (xs, key) => {
            return xs.reduce((rv, x) => {
              (rv[x[key]] = rv[x[key]] || []).push(x);

              return rv;
            }, {});
          };
          const problemsByPath = groupBy(problems, "path");

          for (const path in problemsByPath) {
            const problems = problemsByPath[path];

            problems.forEach((problem) => {
              this.logger.error(
                `${this.capitalizeFirstLetter(problem.type.replace(/-/g, " "))}${
                  problem.value ? ` '${problem.value}'` : ""
                } for the '--${problem.argument}' option${
                  problem.index ? ` by index '${problem.index}'` : ""
                }`,
              );

              if (problem.expected) {
                this.logger.error(`Expected: '${problem.expected}'`);
              }
            });
          }

          process.exit(2);
        }

        // Setup default cache options
        if (item.cache && item.cache.type === "filesystem") {
          const configPath = config.path.get(item);

          if (configPath) {
            if (!item.cache.buildDependencies) {
              item.cache.buildDependencies = {};
            }

            if (!item.cache.buildDependencies.defaultConfig) {
              item.cache.buildDependencies.defaultConfig = [];
            }

            if (Array.isArray(configPath)) {
              configPath.forEach((oneOfConfigPath) => {
                item.cache.buildDependencies.defaultConfig.push(oneOfConfigPath);
              });
            } else {
              item.cache.buildDependencies.defaultConfig.push(configPath);
            }
          }
        }
      }

      // Setup legacy logic for webpack@4
      // TODO respect `--entry-reset` in th next major release
      // TODO drop in the next major release
      if (options.entry) {
        item.entry = options.entry;
      }

      if (options.outputPath) {
        item.output = { ...item.output, ...{ path: path.resolve(options.outputPath) } };
      }

      if (options.target) {
        item.target = options.target;
      }

      if (typeof options.devtool !== "undefined") {
        item.devtool = options.devtool;
      }

      if (options.name) {
        item.name = options.name;
      }

      if (typeof options.stats !== "undefined") {
        item.stats = options.stats;
      }

      if (typeof options.watch !== "undefined") {
        item.watch = options.watch;
      }

      if (typeof options.watchOptionsStdin !== "undefined") {
        item.watchOptions = { ...item.watchOptions, ...{ stdin: options.watchOptionsStdin } };
      }

      if (options.mode) {
        item.mode = options.mode;
      }

      // Respect `process.env.NODE_ENV`
      if (
        !item.mode &&
        process.env &&
        process.env.NODE_ENV &&
        (process.env.NODE_ENV === "development" ||
          process.env.NODE_ENV === "production" ||
          process.env.NODE_ENV === "none")
      ) {
        item.mode = process.env.NODE_ENV;
      }

      // Setup stats
      // TODO remove after drop webpack@4
      const statsForWebpack4 = this.webpack.Stats && this.webpack.Stats.presetToOptions;

      if (statsForWebpack4) {
        if (typeof item.stats === "undefined") {
          item.stats = {};
        } else if (typeof item.stats === "boolean") {
          item.stats = this.webpack.Stats.presetToOptions(item.stats);
        } else if (
          typeof item.stats === "string" &&
          (item.stats === "none" ||
            item.stats === "verbose" ||
            item.stats === "detailed" ||
            item.stats === "normal" ||
            item.stats === "minimal" ||
            item.stats === "errors-only" ||
            item.stats === "errors-warnings")
        ) {
          item.stats = this.webpack.Stats.presetToOptions(item.stats);
        }
      } else {
        if (typeof item.stats === "undefined") {
          item.stats = { preset: "normal" };
        } else if (typeof item.stats === "boolean") {
          item.stats = item.stats ? { preset: "normal" } : { preset: "none" };
        } else if (typeof item.stats === "string") {
          item.stats = { preset: item.stats };
        }
      }

      let colors;

      // From arguments
      if (typeof this.isColorSupportChanged !== "undefined") {
        colors = Boolean(this.isColorSupportChanged);
      }
      // From stats
      else if (typeof item.stats.colors !== "undefined") {
        colors = item.stats.colors;
      }
      // Default
      else {
        colors = Boolean(this.colors.isColorSupported);
      }

      // TODO remove after drop webpack v4
      if (typeof item.stats === "object" && item.stats !== null) {
        item.stats.colors = colors;
      }

      // Apply CLI plugin
      if (!item.plugins) {
        item.plugins = [];
      }

      item.plugins.unshift(
        new CLIPlugin({
          configPath: config.path.get(item),
          helpfulOutput: !options.json,
          hot: options.hot,
          progress: options.progress,
          prefetch: options.prefetch,
          analyze: options.analyze,
        }),
      );

      return options;
    };

    runFunctionOnEachConfig(config.options, internalBuildConfig);

    return config;
  }

  isValidationError(error) {
    // https://github.com/webpack/webpack/blob/master/lib/index.js#L267
    // https://github.com/webpack/webpack/blob/v4.44.2/lib/webpack.js#L90
    const ValidationError =
      this.webpack.ValidationError || this.webpack.WebpackOptionsValidationError;

    return error instanceof ValidationError || error.name === "ValidationError";
  }

  async createCompiler(options, callback) {
    if (typeof options.nodeEnv === "string") {
      process.env.NODE_ENV = options.nodeEnv;
    }

    let config = await this.loadConfig(options);
    config = await this.buildConfig(config, options);

    let compiler;

    try {
      compiler = this.webpack(
        config.options,
        callback
          ? (error, stats) => {
              if (error && this.isValidationError(error)) {
                this.logger.error(error.message);
                process.exit(2);
              }

              callback(error, stats);
            }
          : callback,
      );
    } catch (error) {
      if (this.isValidationError(error)) {
        this.logger.error(error.message);
      } else {
        this.logger.error(error);
      }

      process.exit(2);
    }

    // TODO webpack@4 return Watching and MultiWatching instead Compiler and MultiCompiler, remove this after drop webpack@4
    if (compiler && compiler.compiler) {
      compiler = compiler.compiler;
    }

    return compiler;
  }

  needWatchStdin(compiler) {
    if (compiler.compilers) {
      return compiler.compilers.some(
        (compiler) => compiler.options.watchOptions && compiler.options.watchOptions.stdin,
      );
    }

    return compiler.options.watchOptions && compiler.options.watchOptions.stdin;
  }

  async runWebpack(options, isWatchCommand) {
    // eslint-disable-next-line prefer-const
    let compiler;
    let createJsonStringifyStream;

    if (options.json) {
      const jsonExt = await this.tryRequireThenImport("@discoveryjs/json-ext");

      createJsonStringifyStream = jsonExt.stringifyStream;
    }

    const callback = (error, stats) => {
      if (error) {
        this.logger.error(error);
        process.exit(2);
      }

      if (stats.hasErrors()) {
        process.exitCode = 1;
      }

      if (!compiler) {
        return;
      }

      const statsOptions = compiler.compilers
        ? {
            children: compiler.compilers.map((compiler) =>
              compiler.options ? compiler.options.stats : undefined,
            ),
          }
        : compiler.options
        ? compiler.options.stats
        : undefined;

      // TODO webpack@4 doesn't support `{ children: [{ colors: true }, { colors: true }] }` for stats
      const statsForWebpack4 = this.webpack.Stats && this.webpack.Stats.presetToOptions;

      if (compiler.compilers && statsForWebpack4) {
        statsOptions.colors = statsOptions.children.some((child) => child.colors);
      }

      if (options.json && createJsonStringifyStream) {
        const handleWriteError = (error) => {
          this.logger.error(error);
          process.exit(2);
        };

        if (options.json === true) {
          createJsonStringifyStream(stats.toJson(statsOptions))
            .on("error", handleWriteError)
            .pipe(process.stdout)
            .on("error", handleWriteError)
            .on("close", () => process.stdout.write("\n"));
        } else {
          createJsonStringifyStream(stats.toJson(statsOptions))
            .on("error", handleWriteError)
            .pipe(fs.createWriteStream(options.json))
            .on("error", handleWriteError)
            // Use stderr to logging
            .on("close", () => {
              process.stderr.write(
                `[webpack-cli] ${this.colors.green(
                  `stats are successfully stored as json to ${options.json}`,
                )}\n`,
              );
            });
        }
      } else {
        const printedStats = stats.toString(statsOptions);

        // Avoid extra empty line when `stats: 'none'`
        if (printedStats) {
          this.logger.raw(printedStats);
        }
      }
    };

    const env =
      isWatchCommand || options.watch
        ? { WEBPACK_WATCH: true, ...options.env }
        : { WEBPACK_BUNDLE: true, WEBPACK_BUILD: true, ...options.env };

    options.argv = { ...options, env };

    if (isWatchCommand) {
      options.watch = true;
    }

    compiler = await this.createCompiler(options, callback);

    if (!compiler) {
      return;
    }

    const isWatch = (compiler) =>
      compiler.compilers
        ? compiler.compilers.some((compiler) => compiler.options.watch)
        : compiler.options.watch;

    if (isWatch(compiler) && this.needWatchStdin(compiler)) {
      process.stdin.on("end", () => {
        process.exit(0);
      });
      process.stdin.resume();
    }
  }
}

module.exports = WebpackCLI;
Hacker Blog, Shell İndir, Sql İnjection, XSS Attacks, LFI Attacks, Social Hacking, Exploit Bot, Proxy Tools, Web Shell, PHP Shell, Alfa Shell İndir, Hacking Training Set, DDoS Script, Denial Of Service, Botnet, RFI Attacks, Encryption
Telegram @BIBIL_0DAY