From baf59a330010e719db0309ff1b91b5e27bd07205 Mon Sep 17 00:00:00 2001 From: Tw93 Date: Sat, 24 Jun 2023 00:01:44 +0800 Subject: [PATCH] :sparkles: CLI more beautiful. --- bin/builders/BaseBuilder.ts | 11 ++++--- bin/helpers/merge.ts | 20 ++++++------ bin/helpers/rust.ts | 5 +-- bin/options/icon.ts | 12 ++++--- bin/options/index.ts | 6 ++-- bin/options/logger.ts | 8 ++--- bin/utils/info.ts | 8 +++-- dist/cli.js | 63 +++++++++++++++++++------------------ 8 files changed, 69 insertions(+), 64 deletions(-) diff --git a/bin/builders/BaseBuilder.ts b/bin/builders/BaseBuilder.ts index fc2bdfe..5070195 100644 --- a/bin/builders/BaseBuilder.ts +++ b/bin/builders/BaseBuilder.ts @@ -1,5 +1,6 @@ import path from 'path'; import fsExtra from "fs-extra"; +import chalk from "chalk"; import prompts from 'prompts'; import { PakeAppOptions } from '@/types'; @@ -22,8 +23,8 @@ export default abstract class BaseBuilder { async prepare() { if (!IS_MAC) { - logger.info('The first use requires installing system dependencies.'); - logger.info('See more in https://tauri.app/v1/guides/getting-started/prerequisites#installing.'); + logger.info('⚙︎ The first use requires installing system dependencies.'); + logger.info('⚙︎ See more in https://tauri.app/v1/guides/getting-started/prerequisites.'); } if (!checkRustInstalled()) { @@ -36,7 +37,7 @@ export default abstract class BaseBuilder { if (res.value) { await installRust(); } else { - logger.error('Error: Rust required to package your webapp!'); + logger.error('✕ Rust required to package your webapp.'); process.exit(0); } } @@ -44,7 +45,7 @@ export default abstract class BaseBuilder { const isChina = await isChinaDomain("www.npmjs.com"); const spinner = getSpinner('Installing package...'); if (isChina) { - logger.info("Located in China, using npm/rsProxy CN mirror."); + logger.info("⚙︎ Located in China, using npm/rsProxy CN mirror."); const rustProjectDir = path.join(npmDirectory, 'src-tauri', ".cargo"); await fsExtra.ensureDir(rustProjectDir); const projectCnConf = path.join(npmDirectory, "src-tauri", "rust_proxy.toml"); @@ -54,7 +55,7 @@ export default abstract class BaseBuilder { } else { await shellExec(`cd "${npmDirectory}" && npm install`); } - spinner.succeed('Package installed.'); + spinner.succeed(chalk.green('Package installed!')); } async build(url: string) { diff --git a/bin/helpers/merge.ts b/bin/helpers/merge.ts index 91f240c..5004fb2 100644 --- a/bin/helpers/merge.ts +++ b/bin/helpers/merge.ts @@ -43,7 +43,7 @@ export async function mergeConfig( //Judge the type of URL, whether it is a file or a website. const pathExists = await fsExtra.pathExists(url); if (pathExists) { - logger.warn('Your input might be a local file.'); + logger.warn('✼ Your input might be a local file.'); tauriConf.pake.windows[0].url_type = 'local'; const fileName = path.basename(url); @@ -98,7 +98,7 @@ export async function mergeConfig( tauriConf.tauri.bundle.targets = options.targets === 'all' ? ['deb', 'appimage'] : [options.targets]; } else { logger.warn( - `The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`, + `✼ The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`, ); } } @@ -132,7 +132,7 @@ export async function mergeConfig( if (customIconExt !== iconInfo.fileExt) { updateIconPath = false; - logger.warn(`${iconInfo.message}, but you give ${customIconExt}`); + logger.warn(`✼ ${iconInfo.message}, but you give ${customIconExt}`); tauriConf.tauri.bundle.icon = [iconInfo.defaultIcon]; } else { const iconPath = path.join(npmDirectory, 'src-tauri/', iconInfo.path); @@ -143,12 +143,10 @@ export async function mergeConfig( if (updateIconPath) { tauriConf.tauri.bundle.icon = [options.icon]; } else { - logger.warn(`Icon will remain as default.`); + logger.warn(`✼ Icon will remain as default.`); } } else { - logger.warn( - 'Custom icon path may be invalid. Default icon will be used instead.', - ); + logger.warn('✼ Custom icon path may be invalid, default icon will be used instead.'); tauriConf.tauri.bundle.icon = [iconInfo.defaultIcon]; } @@ -168,13 +166,13 @@ export async function mergeConfig( await fsExtra.copy(systemTrayIcon, trayIcoPath); } else { logger.warn( - `System tray icon must be .ico or .png, but you provided ${iconExt}.`, + `✼ System tray icon must be .ico or .png, but you provided ${iconExt}.`, ); - logger.warn(`Default system tray icon will be used.`); + logger.warn(`✼ Default system tray icon will be used.`); } } catch { - logger.warn(`${systemTrayIcon} not exists!`); - logger.warn(`Default system tray icon will remain unchanged.`); + logger.warn(`✼ ${systemTrayIcon} not exists!`); + logger.warn(`✼ Default system tray icon will remain unchanged.`); } } diff --git a/bin/helpers/rust.ts b/bin/helpers/rust.ts index 4da648d..c15d91f 100644 --- a/bin/helpers/rust.ts +++ b/bin/helpers/rust.ts @@ -1,3 +1,4 @@ +import chalk from "chalk"; import shelljs from 'shelljs'; import { getSpinner } from "@/utils/info"; @@ -16,10 +17,10 @@ export async function installRust() { try { await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac); - spinner.succeed('Rust installed successfully.'); + spinner.succeed(chalk.green('Rust installed successfully!')); } catch (error) { console.error('Error installing Rust:', error.message); - spinner.fail('Rust installation failed.'); + spinner.fail(chalk.red('Rust installation failed!')); process.exit(1); } } diff --git a/bin/options/icon.ts b/bin/options/icon.ts index b465da7..0b6951a 100644 --- a/bin/options/icon.ts +++ b/bin/options/icon.ts @@ -1,13 +1,15 @@ -import { getSpinner } from "@/utils/info"; import path from 'path'; import axios from 'axios'; import fsExtra from "fs-extra"; +import chalk from 'chalk'; import { dir } from 'tmp-promise'; -import { fileTypeFromBuffer } from 'file-type'; + import logger from './logger'; import { npmDirectory } from '@/utils/dir'; import { IS_LINUX, IS_WIN } from '@/utils/platform'; +import { getSpinner } from "@/utils/info"; +import { fileTypeFromBuffer } from 'file-type'; import { PakeAppOptions } from '@/types'; export async function handleIcon(options: PakeAppOptions) { @@ -18,7 +20,7 @@ export async function handleIcon(options: PakeAppOptions) { return path.resolve(options.icon); } } else { - logger.info('No app icon provided, default icon used. Use --icon option to assign an icon.'); + logger.warn('✼ No icon given, default in use. For a custom icon, use --icon option.'); const iconPath = IS_WIN ? 'src-tauri/png/icon_256.ico' : IS_LINUX ? 'src-tauri/png/icon_512.png' : 'src-tauri/icons/icon.icns'; return path.join(npmDirectory, iconPath); } @@ -42,10 +44,10 @@ export async function downloadIcon(iconUrl: string) { const { path: tempPath } = await dir(); const iconPath = `${tempPath}/icon.${fileDetails.ext}`; await fsExtra.outputFile(iconPath, iconData); - spinner.succeed('Icon downloaded successfully.'); + spinner.succeed(chalk.green('Icon downloaded successfully!')); return iconPath; } catch (error) { - spinner.fail('Icon download failed.'); + spinner.fail(chalk.red('Icon download failed!')); if (error.response && error.response.status === 404) { return null; } diff --git a/bin/options/index.ts b/bin/options/index.ts index a2e157a..a8adad2 100644 --- a/bin/options/index.ts +++ b/bin/options/index.ts @@ -34,13 +34,13 @@ export default async function handleOptions(options: PakeCliOptions, url: string } if (!isValidName(name, platform)) { - const LINUX_NAME_ERROR = `Package name is invalid. It should only include lowercase letters, numbers, and dashes, and must contain at least one lowercase letter. Examples: com-123-xxx, 123pan, pan123, weread, we-read.`; - const DEFAULT_NAME_ERROR = `Package name is invalid. It should only include letters and numbers, and must contain at least one letter. Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead.`; + const LINUX_NAME_ERROR = `✕ name should only include lowercase letters, numbers, and dashes, and must contain at least one lowercase letter. Examples: com-123-xxx, 123pan, pan123, weread, we-read.`; + const DEFAULT_NAME_ERROR = `✕ Name should only include letters and numbers, and must contain at least one letter. Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead.`; const errorMsg = platform === 'linux' ? LINUX_NAME_ERROR : DEFAULT_NAME_ERROR; logger.error(errorMsg); if (isActions) { name = resolveAppName(url, platform); - logger.warn(`Inside github actions, use the default name: ${name}`); + logger.warn(`✼ Inside github actions, use the default name: ${name}`); } else { process.exit(1); } diff --git a/bin/options/logger.ts b/bin/options/logger.ts index 5d6b893..6039488 100644 --- a/bin/options/logger.ts +++ b/bin/options/logger.ts @@ -3,19 +3,19 @@ import log from 'loglevel'; const logger = { info(...msg: any[]) { - log.info(...msg.map((m) => chalk.blue.bold(m))); + log.info(...msg.map((m) => chalk.white(m))); }, debug(...msg: any[]) { log.debug(...msg); }, error(...msg: any[]) { - log.error(...msg.map((m) => chalk.red.bold(m))); + log.error(...msg.map((m) => chalk.red(m))); }, warn(...msg: any[]) { - log.info(...msg.map((m) => chalk.yellow.bold(m))); + log.info(...msg.map((m) => chalk.yellow(m))); }, success(...msg: any[]) { - log.info(...msg.map((m) => chalk.green.bold(m))); + log.info(...msg.map((m) => chalk.green(m))); } }; diff --git a/bin/utils/info.ts b/bin/utils/info.ts index 68a1122..21f7992 100644 --- a/bin/utils/info.ts +++ b/bin/utils/info.ts @@ -1,6 +1,7 @@ import crypto from 'crypto'; import prompts from "prompts"; import ora from "ora"; +import chalk from 'chalk'; // Generates an identifier based on the given URL. export function getIdentifier(url: string) { @@ -29,14 +30,15 @@ export function getSpinner(text: string) { const loadingType = { "interval": 80, "frames": [ + "✦", "✶", + "✺", "✵", "✸", + "✴︎", "✹", "✺", - "✹", - "✷", ] } - return ora({ text: `${text}\n`, spinner: loadingType }).start(); + return ora({ text: `${chalk.blue(text)}\n`, spinner: loadingType, color: 'blue' }).start(); } diff --git a/dist/cli.js b/dist/cli.js index 067b910..f790083 100644 --- a/dist/cli.js +++ b/dist/cli.js @@ -342,18 +342,19 @@ function capitalizeFirstLetter(string) { } function getSpinner(text) { const loadingType = { - "interval": 80, + "interval": 100, "frames": [ + "✦", "✶", + "✺", "✵", "✸", + "✴︎", "✹", "✺", - "✹", - "✷", ] }; - return ora({ text: `${text}\n`, spinner: loadingType }).start(); + return ora({ text: `${chalk.blue(text)}\n`, spinner: loadingType, color: 'blue' }).start(); } const { platform: platform$1 } = process; @@ -381,19 +382,19 @@ function shellExec(command) { const logger = { info(...msg) { - log.info(...msg.map((m) => chalk.blue.bold(m))); + log.info(...msg.map((m) => chalk.white(m))); }, debug(...msg) { log.debug(...msg); }, error(...msg) { - log.error(...msg.map((m) => chalk.red.bold(m))); + log.error(...msg.map((m) => chalk.red(m))); }, warn(...msg) { - log.info(...msg.map((m) => chalk.yellow.bold(m))); + log.info(...msg.map((m) => chalk.yellow(m))); }, success(...msg) { - log.info(...msg.map((m) => chalk.green.bold(m))); + log.info(...msg.map((m) => chalk.green(m))); } }; @@ -451,11 +452,11 @@ async function installRust() { const spinner = getSpinner('Downloading Rust...'); try { await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac); - spinner.succeed('Rust installed successfully.'); + spinner.succeed(chalk.green('Rust installed successfully!')); } catch (error) { console.error('Error installing Rust:', error.message); - spinner.fail('Rust installation failed.'); + spinner.fail(chalk.red('Rust installation failed!')); process.exit(1); } } @@ -480,7 +481,7 @@ async function mergeConfig(url, options, tauriConf) { //Judge the type of URL, whether it is a file or a website. const pathExists = await fsExtra.pathExists(url); if (pathExists) { - logger.warn('Your input might be a local file.'); + logger.warn('✼ Your input might be a local file.'); tauriConf.pake.windows[0].url_type = 'local'; const fileName = path.basename(url); const dirName = path.dirname(url); @@ -524,7 +525,7 @@ async function mergeConfig(url, options, tauriConf) { tauriConf.tauri.bundle.targets = options.targets === 'all' ? ['deb', 'appimage'] : [options.targets]; } else { - logger.warn(`The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`); + logger.warn(`✼ The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`); } } // Set icon. @@ -545,7 +546,7 @@ async function mergeConfig(url, options, tauriConf) { fileExt: '.icns', path: `icons/${name.toLowerCase()}.icns`, defaultIcon: 'icons/icon.icns', - message: 'MacOS icon must be .icns type.', + message: 'macOS icon must be .icns type.', }, }; const iconInfo = platformIconMap[platform]; @@ -555,7 +556,7 @@ async function mergeConfig(url, options, tauriConf) { let customIconExt = path.extname(options.icon).toLowerCase(); if (customIconExt !== iconInfo.fileExt) { updateIconPath = false; - logger.warn(`${iconInfo.message}, but you give ${customIconExt}`); + logger.warn(`✼ ${iconInfo.message}, but you give ${customIconExt}`); tauriConf.tauri.bundle.icon = [iconInfo.defaultIcon]; } else { @@ -567,11 +568,11 @@ async function mergeConfig(url, options, tauriConf) { tauriConf.tauri.bundle.icon = [options.icon]; } else { - logger.warn(`Icon will remain as default.`); + logger.warn(`✼ Icon will remain as default.`); } } else { - logger.warn('Custom icon path may be invalid. Default icon will be used instead.'); + logger.warn('✼ Custom icon path may be invalid, default icon will be used instead.'); tauriConf.tauri.bundle.icon = [iconInfo.defaultIcon]; } // Set tray icon path. @@ -587,13 +588,13 @@ async function mergeConfig(url, options, tauriConf) { await fsExtra.copy(systemTrayIcon, trayIcoPath); } else { - logger.warn(`System tray icon must be .ico or .png, but you provided ${iconExt}.`); - logger.warn(`Default system tray icon will be used.`); + logger.warn(`✼ System tray icon must be .ico or .png, but you provided ${iconExt}.`); + logger.warn(`✼ Default system tray icon will be used.`); } } catch { - logger.warn(`${systemTrayIcon} not exists!`); - logger.warn(`Default system tray icon will remain unchanged.`); + logger.warn(`✼ ${systemTrayIcon} not exists!`); + logger.warn(`✼ Default system tray icon will remain unchanged.`); } } tauriConf.tauri.systemTray.iconPath = trayIconPath; @@ -621,8 +622,8 @@ class BaseBuilder { } async prepare() { if (!IS_MAC) { - logger.info('The first use requires installing system dependencies.'); - logger.info('See more in https://tauri.app/v1/guides/getting-started/prerequisites#installing.'); + logger.info('⚙︎ The first use requires installing system dependencies.'); + logger.info('⚙︎ See more in https://tauri.app/v1/guides/getting-started/prerequisites.'); } if (!checkRustInstalled()) { const res = await prompts({ @@ -634,14 +635,14 @@ class BaseBuilder { await installRust(); } else { - logger.error('Error: Rust required to package your webapp!'); + logger.error('✕ Rust required to package your webapp.'); process.exit(0); } } const isChina = await isChinaDomain("www.npmjs.com"); const spinner = getSpinner('Installing package...'); if (isChina) { - logger.info("Located in China, using npm/rsProxy CN mirror."); + logger.info("⚙︎ Located in China, using npm/rsProxy CN mirror."); const rustProjectDir = path.join(npmDirectory, 'src-tauri', ".cargo"); await fsExtra.ensureDir(rustProjectDir); const projectCnConf = path.join(npmDirectory, "src-tauri", "rust_proxy.toml"); @@ -652,7 +653,7 @@ class BaseBuilder { else { await shellExec(`cd "${npmDirectory}" && npm install`); } - spinner.succeed('Package installed.'); + spinner.succeed(chalk.green('Package installed!')); } async build(url) { await this.buildAndCopy(url, this.options.targets); @@ -800,7 +801,7 @@ async function handleIcon(options) { } } else { - logger.info('No app icon provided, default icon used. Use --icon option to assign an icon.'); + logger.warn('✼ No icon given, default in use. For a custom icon, use --icon option.'); const iconPath = IS_WIN ? 'src-tauri/png/icon_256.ico' : IS_LINUX ? 'src-tauri/png/icon_512.png' : 'src-tauri/icons/icon.icns'; return path.join(npmDirectory, iconPath); } @@ -820,11 +821,11 @@ async function downloadIcon(iconUrl) { const { path: tempPath } = await dir(); const iconPath = `${tempPath}/icon.${fileDetails.ext}`; await fsExtra.outputFile(iconPath, iconData); - spinner.succeed('Icon downloaded successfully.'); + spinner.succeed(chalk.green('Icon downloaded successfully!')); return iconPath; } catch (error) { - spinner.fail('Icon download failed.'); + spinner.fail(chalk.red('Icon download failed!')); if (error.response && error.response.status === 404) { return null; } @@ -895,13 +896,13 @@ async function handleOptions(options, url) { name = namePrompt || defaultName; } if (!isValidName(name, platform)) { - const LINUX_NAME_ERROR = `Package name is invalid. It should only include lowercase letters, numbers, and dashes, and must contain at least one lowercase letter. Examples: com-123-xxx, 123pan, pan123, weread, we-read.`; - const DEFAULT_NAME_ERROR = `Package name is invalid. It should only include letters and numbers, and must contain at least one letter. Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead.`; + const LINUX_NAME_ERROR = `✕ Package name is invalid. It should only include lowercase letters, numbers, and dashes, and must contain at least one lowercase letter. Examples: com-123-xxx, 123pan, pan123, weread, we-read.`; + const DEFAULT_NAME_ERROR = `✕ Package name is invalid. It should only include letters and numbers, and must contain at least one letter. Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead.`; const errorMsg = platform === 'linux' ? LINUX_NAME_ERROR : DEFAULT_NAME_ERROR; logger.error(errorMsg); if (isActions) { name = resolveAppName(url, platform); - logger.warn(`Inside github actions, use the default name: ${name}`); + logger.warn(`✼ Inside github actions, use the default name: ${name}`); } else { process.exit(1);