From 58414f05cb325d3e42dd26396e7b91a659e57f2e Mon Sep 17 00:00:00 2001 From: PierreDemailly Date: Fri, 30 Dec 2022 16:52:40 +0100 Subject: [PATCH] feat: improve cliui design --- package-lock.json | 87 ++++++++++++++++++++++++++++++++++++----- package.json | 2 +- src/commands/summary.js | 24 +++++++----- src/commands/verify.js | 64 ++++++++++++++++-------------- 4 files changed, 126 insertions(+), 51 deletions(-) diff --git a/package-lock.json b/package-lock.json index c25ff971..90f7394d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,9 +19,9 @@ "@nodesecure/utils": "^1.0.0", "@nodesecure/vuln": "^1.7.0", "@polka/send-type": "^0.5.2", + "@topcli/cliui": "^1.1.0", "@topcli/spinner": "^1.1.0", "cacache": "^17.0.2", - "cliui": "^7.0.4", "dotenv": "^16.0.3", "filenamify": "^5.1.1", "kleur": "^4.1.4", @@ -1996,6 +1996,38 @@ "node": ">= 10" } }, + "node_modules/@topcli/cliui": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@topcli/cliui/-/cliui-1.1.0.tgz", + "integrity": "sha512-et+hklBvhhCmz9wTZda2yowOFhjBPMhHfP7nm1H42P07W4XLqBC6VHTM5HYaipcuJftwtnbOPKSd87UsvJN8Lw==", + "dependencies": { + "@topcli/wcwidth": "^1.0.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=16.16" + } + }, + "node_modules/@topcli/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@topcli/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@topcli/spinner": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@topcli/spinner/-/spinner-1.1.0.tgz", @@ -2820,6 +2852,7 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -2830,6 +2863,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -2837,12 +2871,14 @@ "node_modules/cliui/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/cliui/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2856,6 +2892,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5345,9 +5382,9 @@ } }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", + "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -9986,6 +10023,31 @@ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" }, + "@topcli/cliui": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@topcli/cliui/-/cliui-1.1.0.tgz", + "integrity": "sha512-et+hklBvhhCmz9wTZda2yowOFhjBPMhHfP7nm1H42P07W4XLqBC6VHTM5HYaipcuJftwtnbOPKSd87UsvJN8Lw==", + "requires": { + "@topcli/wcwidth": "^1.0.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, "@topcli/spinner": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@topcli/spinner/-/spinner-1.1.0.tgz", @@ -10524,6 +10586,7 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -10533,17 +10596,20 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10554,6 +10620,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -12294,9 +12361,9 @@ "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==" }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", + "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==", "dev": true }, "jsonparse": { diff --git a/package.json b/package.json index 23cad1e4..654c1aac 100644 --- a/package.json +++ b/package.json @@ -80,9 +80,9 @@ "@nodesecure/utils": "^1.0.0", "@nodesecure/vuln": "^1.7.0", "@polka/send-type": "^0.5.2", + "@topcli/cliui": "^1.1.0", "@topcli/spinner": "^1.1.0", "cacache": "^17.0.2", - "cliui": "^7.0.4", "dotenv": "^16.0.3", "filenamify": "^5.1.1", "kleur": "^4.1.4", diff --git a/src/commands/summary.js b/src/commands/summary.js index 330f1225..19b07ec7 100644 --- a/src/commands/summary.js +++ b/src/commands/summary.js @@ -3,25 +3,29 @@ import fs from "fs/promises"; import path from "path"; // Import Third-party Dependencies -import cliui from "cliui"; +import cliui from "@topcli/cliui"; import kleur from "kleur"; import * as i18n from "@nodesecure/i18n"; import { formatBytes } from "@nodesecure/utils"; // VARS -const { yellow, gray, white, green, cyan, red } = kleur; +const { yellow, grey, white, green, cyan, red } = kleur; + +function separatorLine() { + return grey("-".repeat(80)); +} export async function main(json = "nsecure-result.json") { const dataFilePath = path.join(process.cwd(), json); const rawAnalysis = await fs.readFile(dataFilePath, { encoding: "utf-8" }); const { rootDependencyName, dependencies } = JSON.parse(rawAnalysis); - const ui = cliui(); + const ui = cliui({ width: 80 }); const title = `${white().bold(`${i18n.getToken("ui.stats.title")}:`)} ${cyan().bold(rootDependencyName)}`; ui.div( { text: title, width: 50 } ); - ui.div({ text: gray("-------------------------------------------------------------------"), width: 70 }); + ui.div({ text: separatorLine() }); if (dependencies) { const { @@ -34,15 +38,15 @@ export async function main(json = "nsecure-result.json") { ui.div( { text: white().bold(`${i18n.getToken("ui.stats.total_packages")}:`), width: 60 }, - { text: green().bold(`${packagesCount}`), width: 20 } + { text: green().bold(`${packagesCount}`), width: 20, align: "right" } ); ui.div( { text: white().bold(`${i18n.getToken("ui.stats.total_size")}:`), width: 60 }, - { text: green().bold(`${formatBytes(totalSize)}`), width: 20 } + { text: green().bold(`${formatBytes(totalSize)}`), width: 20, align: "right" } ); ui.div( { text: white().bold(`${i18n.getToken("ui.stats.indirect_deps")}:`), width: 60 }, - { text: green().bold(`${packageWithIndirectDeps}`), width: 20 } + { text: green().bold(`${packageWithIndirectDeps}`), width: 20, align: "right" } ); ui.div(""); @@ -52,7 +56,7 @@ export async function main(json = "nsecure-result.json") { const extensionEntries = Object.entries(extensionMap); ui.div( { - text: `${extensionEntries.reduce(buildStringFromEntries, "")}`, width: 70 + text: `${extensionEntries.reduce(buildStringFromEntries, "")}` } ); @@ -63,7 +67,7 @@ export async function main(json = "nsecure-result.json") { const licenceEntries = Object.entries(licenceMap); ui.div( { - text: yellow().bold(`${licenceEntries.reduce(buildStringFromEntries, "")}`), width: 70 + text: yellow().bold(`${licenceEntries.reduce(buildStringFromEntries, "")}`) } ); } @@ -73,7 +77,7 @@ export async function main(json = "nsecure-result.json") { { text: yellow().bold("No dependencies"), width: 30 } ); } - ui.div({ text: gray("-------------------------------------------------------------------"), width: 70 }); + ui.div({ text: separatorLine() }); console.log(ui.toString()); return void 0; diff --git a/src/commands/verify.js b/src/commands/verify.js index 2492113b..d9708b7a 100644 --- a/src/commands/verify.js +++ b/src/commands/verify.js @@ -1,5 +1,5 @@ // Import Third-party Dependencies -import cliui from "cliui"; +import cliui from "@topcli/cliui"; import kleur from "kleur"; import { verify } from "@nodesecure/scanner"; import { formatBytes, locationToString } from "@nodesecure/utils"; @@ -7,6 +7,10 @@ import { formatBytes, locationToString } from "@nodesecure/utils"; // VARS const { yellow, grey, white, green, cyan, red, magenta } = kleur; +function separatorLine() { + return grey("-".repeat(80)); +} + export async function main(packageName = null, options) { const payload = await verify(packageName); if (options.json) { @@ -14,7 +18,7 @@ export async function main(packageName = null, options) { } const { files, directorySize, uniqueLicenseIds, ast } = payload; - const ui = cliui(); + const ui = cliui({ width: 80 }); ui.div( { text: cyan().bold("directory size:"), width: 20 }, { text: yellow().bold(formatBytes(directorySize)), width: 10 } @@ -28,8 +32,8 @@ export async function main(packageName = null, options) { { ui.div( - { text: white().bold("ext"), width: 15, align: "center" }, - { text: white().bold("files"), width: 45 }, + { text: white().bold("ext"), width: 10, align: "center" }, + { text: white().bold("files"), width: 40 }, { text: white().bold("minified files"), width: 30 } ); @@ -41,8 +45,8 @@ export async function main(packageName = null, options) { for (const [ext, file, min] of divArray) { ui.div( - { text: cyan().bold(ext), width: 15, align: "center" }, - { text: file, width: 45 }, + { text: cyan().bold(ext), width: 10, align: "center" }, + { text: file, width: 40 }, { text: red().bold(min), width: 30 } ); } @@ -50,43 +54,43 @@ export async function main(packageName = null, options) { console.log(`${ui.toString()}\n`); ui.resetOutput(); - ui.div({ text: grey("-------------------------------------------------------------------"), width: 70 }); - ui.div({ text: cyan().bold("Required dependency and files"), width: 70, align: "center" }); - ui.div({ text: grey("-------------------------------------------------------------------"), width: 70 }); - ui.div({ text: "\n", width: 70, align: "center" }); + ui.div({ text: separatorLine() }); + ui.div({ text: cyan().bold("Required dependency and files"), align: "center" }); + ui.div({ text: separatorLine() }); + ui.div(); for (const [fileName, deps] of Object.entries(ast.dependencies)) { - ui.div({ text: magenta().bold(fileName), width: 70, align: "center" }); - ui.div({ text: grey("-------------------------------------------------------------------"), width: 70 }); + ui.div({ text: magenta().bold(fileName), align: "center" }); + ui.div({ text: separatorLine() }); ui.div( - { text: white().bold("required stmt"), width: 32, align: "left" }, - { text: white().bold("try/catch"), width: 12, align: "center" }, - { text: white().bold("source location"), width: 26, align: "center" } + { text: white().bold("required stmt"), width: 30 }, + { text: white().bold("try/catch"), width: 20, align: "center" }, + { text: white().bold("source location"), width: 30, align: "right" } ); for (const [depName, infos] of Object.entries(deps)) { const { start, end } = infos.location; const position = `[${start.line}:${start.column}] - [${end.line}:${end.column}]`; ui.div( - { text: depName, width: 32 }, - { text: (infos.inTry ? green : red)().bold(infos.inTry), width: 12, align: "center" }, - { text: grey().bold(position), width: 26, align: "center" } + { text: depName, width: 30 }, + { text: (infos.inTry ? green : red)().bold(infos.inTry), width: 20, align: "center" }, + { text: grey().bold(position), width: 30, align: "right" } ); } - ui.div({ text: "", width: 70, align: "center" }); + ui.div(); console.log(`${ui.toString()}`); ui.resetOutput(); } - ui.div({ text: grey("-------------------------------------------------------------------"), width: 70 }); - ui.div({ text: cyan().bold("AST Warnings"), width: 70, align: "center" }); - ui.div({ text: grey("-------------------------------------------------------------------"), width: 70 }); - ui.div({ text: "", width: 70, align: "center" }); + ui.div({ text: separatorLine() }); + ui.div({ text: cyan().bold("AST Warnings"), align: "center" }); + ui.div({ text: separatorLine() }); + ui.div(); ui.div( { text: white().bold("file"), width: 30 }, - { text: white().bold("kind"), width: 15, align: "center" }, - { text: white().bold("source location"), width: 25, align: "center" } + { text: white().bold("kind"), width: 20, align: "center" }, + { text: white().bold("source location"), width: 30, align: "right" } ); for (const warning of ast.warnings) { @@ -96,14 +100,14 @@ export async function main(packageName = null, options) { ui.div( { text: warning.file || grey().bold("NONE"), width: 30 }, - { text: magenta().bold(warning.kind), width: 15, align: "center" }, - { text: grey().bold(position), width: 25, align: "center" } + { text: magenta().bold(warning.kind), width: 20, align: "center" }, + { text: grey().bold(position), width: 30, align: "right" } ); if (warning.value) { - ui.div({ text: "", width: 70, align: "center" }); - ui.div({ text: yellow().bold(warning.value), width: 70, align: "center" }); + ui.div(); + ui.div({ text: yellow().bold(warning.value), align: "center" }); } - ui.div({ text: grey("-------------------------------------------------------------------"), width: 70 }); + ui.div({ text: separatorLine() }); } console.log(`${ui.toString()}`);