Skip to content

Commit

Permalink
refactor: run info under the hood for the version command (#3370)
Browse files Browse the repository at this point in the history
  • Loading branch information
snitin315 committed Sep 24, 2022
1 parent c7c5f08 commit f2f05df
Show file tree
Hide file tree
Showing 11 changed files with 337 additions and 521 deletions.
6 changes: 0 additions & 6 deletions packages/info/package.json
Expand Up @@ -19,15 +19,9 @@
"files": [
"lib"
],
"dependencies": {
"envinfo": "^7.7.3"
},
"gitHead": "fb50f766851f500ca12867a2aa9de81fa6e368f9",
"peerDependencies": {
"webpack": "5.x.x",
"webpack-cli": "4.x.x"
},
"devDependencies": {
"@types/envinfo": "^7.8.1"
}
}
85 changes: 2 additions & 83 deletions packages/info/src/index.ts
@@ -1,15 +1,5 @@
import envinfo from "envinfo";
import { IWebpackCLI } from "webpack-cli";

interface Information {
Binaries?: string[];
Browsers?: string[];
Monorepos?: string[];
System?: string[];
npmGlobalPackages?: string[];
npmPackages?: string | string[];
}

class InfoCommand {
async apply(cli: IWebpackCLI): Promise<void> {
await cli.makeCommand(
Expand All @@ -20,80 +10,9 @@ class InfoCommand {
usage: "[options]",
pkg: "@webpack-cli/info",
},
[
{
name: "output",
alias: "o",
configs: [
{
type: "string",
},
],
description: "To get the output in a specified format ( accept json or markdown )",
},
{
name: "additional-package",
alias: "a",
configs: [{ type: "string" }],
multiple: true,
description: "Adds additional packages to the output",
},
],
cli.getInfoOptions(),
async (options: { output: string; additionalPackage: string[] }) => {
let { output } = options;

const envinfoConfig: { [key: string]: boolean } = {};

if (output) {
// Remove quotes if exist
output = output.replace(/['"]+/g, "");

switch (output) {
case "markdown":
envinfoConfig["markdown"] = true;
break;
case "json":
envinfoConfig["json"] = true;
break;
default:
cli.logger.error(`'${output}' is not a valid value for output`);
process.exit(2);
}
}

const defaultInformation: Information = {
Binaries: ["Node", "Yarn", "npm"],
Browsers: [
"Brave Browser",
"Chrome",
"Chrome Canary",
"Edge",
"Firefox",
"Firefox Developer Edition",
"Firefox Nightly",
"Internet Explorer",
"Safari",
"Safari Technology Preview",
],
Monorepos: ["Yarn Workspaces", "Lerna"],
System: ["OS", "CPU", "Memory"],
npmGlobalPackages: ["webpack", "webpack-cli", "webpack-dev-server"],
};

let defaultPackages: string[] = ["webpack", "loader", "@webpack-cli/"];

if (typeof options.additionalPackage !== "undefined") {
defaultPackages = [...defaultPackages, ...options.additionalPackage];
}

defaultInformation.npmPackages = `{${defaultPackages
.map((item) => `*${item}*`)
.join(",")}}`;

let info = await envinfo.run(defaultInformation, envinfoConfig);

info = info.replace(/npmPackages/g, "Packages");
info = info.replace(/npmGlobalPackages/g, "Global Packages");
const info = await cli.getInfoOutput(options);

cli.logger.raw(info);
},
Expand Down
4 changes: 4 additions & 0 deletions packages/webpack-cli/package.json
Expand Up @@ -41,12 +41,16 @@
"colorette": "^2.0.14",
"commander": "^7.0.0",
"cross-spawn": "^7.0.3",
"envinfo": "^7.7.3",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2",
"interpret": "^2.2.0",
"rechoir": "^0.7.0",
"webpack-merge": "^5.7.3"
},
"devDependencies": {
"@types/envinfo": "^7.8.1"
},
"peerDependencies": {
"webpack": "5.x.x"
},
Expand Down
2 changes: 2 additions & 0 deletions packages/webpack-cli/src/types.ts
Expand Up @@ -47,6 +47,8 @@ interface IWebpackCLI {
doInstall(packageName: string, options?: PackageInstallOptions): Promise<string>;
loadJSONFile<T = unknown>(path: Path, handleError: boolean): Promise<T>;
tryRequireThenImport<T = unknown>(module: ModuleName, handleError: boolean): Promise<T>;
getInfoOptions(): WebpackCLIBuiltInOption[];
getInfoOutput(options: { output: string; additionalPackage: string[] }): Promise<string>;
makeCommand(
commandOptions: WebpackCLIOptions,
options: WebpackCLICommandOptions,
Expand Down
193 changes: 103 additions & 90 deletions packages/webpack-cli/src/webpack-cli.ts
Expand Up @@ -19,7 +19,6 @@ import {
WebpackConfiguration,
Argv,
BasicPrimitive,
BasicPackageJsonContent,
CallableOption,
Callback,
CLIPluginOptions,
Expand Down Expand Up @@ -58,10 +57,20 @@ const { pathToFileURL } = require("url");
const util = require("util");

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

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

interface Information {
Binaries?: string[];
Browsers?: string[];
Monorepos?: string[];
System?: string[];
npmGlobalPackages?: string[];
npmPackages?: string | string[];
}

class WebpackCLI implements IWebpackCLI {
colors: WebpackCLIColors;
logger: WebpackCLILogger;
Expand Down Expand Up @@ -359,6 +368,84 @@ class WebpackCLI implements IWebpackCLI {
return result;
}

getInfoOptions(): WebpackCLIBuiltInOption[] {
return [
{
name: "output",
alias: "o",
configs: [
{
type: "string",
},
],
description: "To get the output in a specified format ( accept json or markdown )",
},
{
name: "additional-package",
alias: "a",
configs: [{ type: "string" }],
multiple: true,
description: "Adds additional packages to the output",
},
];
}

async getInfoOutput(options: { output: string; additionalPackage: string[] }): Promise<string> {
let { output } = options;
const envinfoConfig: { [key: string]: boolean } = {};

if (output) {
// Remove quotes if exist
output = output.replace(/['"]+/g, "");

switch (output) {
case "markdown":
envinfoConfig["markdown"] = true;
break;
case "json":
envinfoConfig["json"] = true;
break;
default:
this.logger.error(`'${output}' is not a valid value for output`);
process.exit(2);
}
}

const defaultInformation: Information = {
Binaries: ["Node", "Yarn", "npm"],
Browsers: [
"Brave Browser",
"Chrome",
"Chrome Canary",
"Edge",
"Firefox",
"Firefox Developer Edition",
"Firefox Nightly",
"Internet Explorer",
"Safari",
"Safari Technology Preview",
],
Monorepos: ["Yarn Workspaces", "Lerna"],
System: ["OS", "CPU", "Memory"],
npmGlobalPackages: ["webpack", "webpack-cli", "webpack-dev-server"],
};

let defaultPackages: string[] = ["webpack", "loader", "@webpack-cli/"];

if (typeof options.additionalPackage !== "undefined") {
defaultPackages = [...defaultPackages, ...options.additionalPackage];
}

defaultInformation.npmPackages = `{${defaultPackages.map((item) => `*${item}*`).join(",")}}`;

let info = await envinfo.run(defaultInformation, envinfoConfig);

info = info.replace(/npmPackages/g, "Packages");
info = info.replace(/npmGlobalPackages/g, "Global Packages");

return info;
}

async makeCommand(
commandOptions: WebpackCLIOptions,
options: WebpackCLICommandOptions,
Expand Down Expand Up @@ -925,8 +1012,9 @@ class WebpackCLI implements IWebpackCLI {
dependencies: [WEBPACK_PACKAGE],
};
const versionCommandOptions = {
name: "version [commands...]",
name: "version",
alias: "v",
usage: "[options]",
description:
"Output the version number of 'webpack', 'webpack-cli' and 'webpack-dev-server' and commands.",
};
Expand Down Expand Up @@ -1044,8 +1132,15 @@ class WebpackCLI implements IWebpackCLI {
this.makeCommand(helpCommandOptions, [], () => {});
} else if (isCommand(commandName, versionCommandOptions)) {
// Stub for the `version` command
// eslint-disable-next-line @typescript-eslint/no-empty-function
this.makeCommand(versionCommandOptions, [], () => {});
this.makeCommand(
versionCommandOptions,
this.getInfoOptions(),
async (options: { output: string; additionalPackage: string[] }) => {
const info = await cli.getInfoOutput(options);

cli.logger.raw(info);
},
);
} else {
const builtInExternalCommandInfo = externalBuiltInCommandsInfo.find(
(externalBuiltInCommandInfo) =>
Expand Down Expand Up @@ -1181,84 +1276,6 @@ class WebpackCLI implements IWebpackCLI {
cli.colors = cli.createColors(color);
});

// Make `-v, --version` options
// Make `version|v [commands...]` command
const outputVersion = async (options: string[]) => {
// 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) as WebpackCLICommand;

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<BasicPackageJsonContent>(
`${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<BasicPackageJsonContent>("../package.json");

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

let devServer;

try {
devServer = await this.loadJSONFile<BasicPackageJsonContent>(
"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.",
Expand Down Expand Up @@ -1625,15 +1642,11 @@ class WebpackCLI implements IWebpackCLI {
}

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

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

await outputVersion(optionsForVersion);
if (isVersionOption) {
const info = await this.getInfoOutput({ output: "", additionalPackage: [] });
this.logger.raw(info);
process.exit(0);
}

let commandToRun = operand;
Expand Down
2 changes: 1 addition & 1 deletion smoketests/missing-packages/webpack.test.js
Expand Up @@ -37,7 +37,7 @@ const serveCommand = () => {
const versionCommand = () => {
const packageName = "webpack";
const args = ["version"];
const logMessage = "webpack-cli:";
const logMessage = "System:";

return runTestStdout({ packageName, cliArgs: args, logMessage });
};
Expand Down

0 comments on commit f2f05df

Please sign in to comment.