简易版chalk

简易版chalk

参考文档

“ANSI 转义序列(ANSI escape sequences)是一种带内信号的转义序列标准,用于控制视频文本终端上的光标位置、颜色和其他选项。在文本中嵌入确定的字节序列,大部分以 ESC 转义字符和"["字符开始,终端会把这些字节序列解释为相应的指令,而不是普通的字符编码。”

根据描述我们知道需要使用一些特殊的转义字符来实现不同字体风格、颜色、背景色。

1、字体风格

根据wiki选择图形再现(SGR)参数的描述编写 Ansi 码表,同时获取一下码表的key

在这里插入图片描述

/**
 * ESC 按键的 Ansi 码
 */
export const ESC_CODE: string = "\u001B"

/**
 * 图形再现参数的 Ansi 码表1(开启)
 */
const Style1 = {
    // 前景色
    'foreground': '38;2;',
    // 背景色
    'background': '48;2;',
    // 加粗
    'bold': '1',
    // 暗淡
    'dim': '2',
    // 倾斜
    'italic': '3',
    // 下划线
    'underline': '4',
    // 闪烁
    'flick': '5',
    // 快速闪烁
    'fast_flick': '6',
    // 反转
    'inverse': '7',
    // 隐藏
    'hidden': '8',
    // 删除线
    'strikethrough': '9',
    // 上划线
    'overline': '53',
};

/**
 * 图形再现参数的 Ansi 码表2(关闭)
 */
const Style2 = {
    // 前景色
    'foreground': '39',
    // 背景色
    'background': '49',
    // 加粗
    'bold': '22',
    // 暗淡
    'dim': '22',
    // 倾斜
    'italic': '23',
    // 下划线
    'underline': '24',
    // 闪烁
    'flick': '25',
    // 快速闪烁
    'fast_flick': '25',
    // 反转
    'inverse': '27',
    // 隐藏
    'hidden': '28',
    // 删除线
    'strikethrough': '29',
    // 上划线
    'overline': '55',
};

export type Style1 = keyof typeof Style1
export const EscapeSequence1 = (key: Style1, ...args: any[]) => {
    const code = Style1[key];
    // return String.raw`${ESC_CODE}[${code}${args.join(';')}m`;
    return `${ESC_CODE}[${code}${args.join(';')}m`;
}

export type Style2 = keyof typeof Style2
export const EscapeSequence2 = (key: Style2) => {
    const code = Style2[key]
    // return String.raw`${ESC_CODE}[${code}m`;
    return `${ESC_CODE}[${code}m`;
}

export type Styles = Style1 & Style2

2、颜色

这里不再像chalk一样支持3/4位颜色、8位颜色,而是仅仅支持真彩色(TrueColor),根据wiki颜色的描述补充 Ansi 码表的foregroundbackground

在这里插入图片描述

这里需要先判断一下终端是否支持真彩色(并未给出所有平台的判断方案)。

import process from "node:process";
import os from "node:os";
import {execSync} from 'child_process';

/**
 * 判断是否支持当前环境是否支持 TrueColor
 * @returns {boolean} 是否支持 TrueColor
 */
export default (): boolean => {
    if (process.platform === 'win32') {
        // Windows 10 build 14931 is the first release that supports 16m/TrueColor.
        const osRelease = os.release().split('.');
        return Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 14_931;
    } else if (process.platform === 'darwin') {
        const result = execSync('tput colors');
        const numColors = parseInt(result.toString().trim(), 10);
        return numColors >= 256;
    }
    return false;
}

颜色名称根据 CSS3 种的 147 个名称去定义。

/**
 * CSS3 标准中的 147 中颜色定义
 */
export const ColorMapping = {
    "aliceblue": "#f0f8ff",
    "antiquewhite": "#faebd7",
    "aqua": "#00ffff",
    "aquamarine": "#7fffd4",
    "azure": "#f0ffff",
    "beige": "#f5f5dc",
    "bisque": "#ffe4c4",
    "black": "#000000",
    "blanchedalmond": "#ffebcd",
    "blue": "#0000ff",
    "blueviolet": "#8a2be2",
    "brown": "#a52a2a",
    "burlywood": "#deb887",
    "cadetblue": "#5f9ea0",
    "chartreuse": "#7fff00",
    "chocolate": "#d2691e",
    "coral": "#ff7f50",
    "cornflowerblue": "#6495ed",
    "cornsilk": "#fff8dc",
    "crimson": "#dc143c",
    "cyan": "#00ffff",
    "darkblue": "#00008b",
    "darkcyan": "#008b8b",
    "darkgoldenrod": "#b8860b",
    "darkgray": "#a9a9a9",
    "darkgreen": "#006400",
    "darkgrey": "#a9a9a9",
    "darkkhaki": "#bdb76b",
    "darkmagenta": "#8b008b",
    "darkolivegreen": "#556b2f",
    "darkorange": "#ff8c00",
    "darkorchid": "#9932cc",
    "darkred": "#8b0000",
    "darksalmon": "#e9967a",
    "darkseagreen": "#8fbc8f",
    "darkslateblue": "#483d8b",
    "darkslategray": "#2f4f4f",
    "darkslategrey": "#2f4f4f",
    "darkturquoise": "#00ced1",
    "darkviolet": "#9400d3",
    "deeppink": "#ff1493",
    "deepskyblue": "#00bfff",
    "dimgray": "#696969",
    "dimgrey": "#696969",
    "dodgerblue": "#1e90ff",
    "firebrick": "#b22222",
    "floralwhite": "#fffaf0",
    "forestgreen": "#228b22",
    "fuchsia": "#ff00ff",
    "gainsboro": "#dcdcdc",
    "ghostwhite": "#f8f8ff",
    "gold": "#ffd700",
    "goldenrod": "#daa520",
    "gray": "#808080",
    "green": "#008000",
    "greenyellow": "#adff2f",
    "grey": "#808080",
    "honeydew": "#f0fff0",
    "hotpink": "#ff69b4",
    "indianred": "#cd5c5c",
    "indigo": "#4b0082",
    "ivory": "#fffff0",
    "khaki": "#f0e68c",
    "lavender": "#e6e6fa",
    "lavenderblush": "#fff0f5",
    "lawngreen": "#7cfc00",
    "lemonchiffon": "#fffacd",
    "lightblue": "#add8e6",
    "lightcoral": "#f08080",
    "lightcyan": "#e0ffff",
    "lightgoldenrodyellow": "#fafad2",
    "lightgray": "#d3d3d3",
    "lightgreen": "#90ee90",
    "lightgrey": "#d3d3d3",
    "lightpink": "#ffb6c1",
    "lightsalmon": "#ffa07a",
    "lightseagreen": "#20b2aa",
    "lightskyblue": "#87cefa",
    "lightslategray": "#778899",
    "lightslategrey": "#778899",
    "lightsteelblue": "#b0c4de",
    "lightyellow": "#ffffe0",
    "lime": "#00ff00",
    "limegreen": "#32cd32",
    "linen": "#faf0e6",
    "magenta": "#ff00ff",
    "maroon": "#800000",
    "mediumaquamarine": "#66cdaa",
    "mediumblue": "#0000cd",
    "mediumorchid": "#ba55d3",
    "mediumpurple": "#9370db",
    "mediumseagreen": "#3cb371",
    "mediumslateblue": "#7b68ee",
    "mediumspringgreen": "#00fa9a",
    "mediumturquoise": "#48d1cc",
    "mediumvioletred": "#c71585",
    "midnightblue": "#191970",
    "mintcream": "#f5fffa",
    "mistyrose": "#ffe4e1",
    "moccasin": "#ffe4b5",
    "navajowhite": "#ffdead",
    "navy": "#000080",
    "oldlace": "#fdf5e6",
    "olive": "#808000",
    "olivedrab": "#6b8e23",
    "orange": "#ffa500",
    "orangered": "#ff4500",
    "orchid": "#da70d6",
    "palegoldenrod": "#eee8aa",
    "palegreen": "#98fb98",
    "paleturquoise": "#afeeee",
    "palevioletred": "#db7093",
    "papayawhip": "#ffefd5",
    "peachpuff": "#ffdab9",
    "peru": "#cd853f",
    "pink": "#ffc0cb",
    "plum": "#dda0dd",
    "powderblue": "#b0e0e6",
    "purple": "#800080",
    "red": "#ff0000",
    "rosybrown": "#bc8f8f",
    "royalblue": "#4169e1",
    "saddlebrown": "#8b4513",
    "salmon": "#fa8072",
    "sandybrown": "#f4a460",
    "seagreen": "#2e8b57",
    "seashell": "#fff5ee",
    "sienna": "#a0522d",
    "silver": "#c0c0c0",
    "skyblue": "#87ceeb",
    "slateblue": "#6a5acd",
    "slategray": "#708090",
    "slategrey": "#708090",
    "snow": "#fffafa",
    "springgreen": "#00ff7f",
    "steelblue": "#4682b4",
    "tan": "#d2b48c",
    "teal": "#008080",
    "thistle": "#d8bfd8",
    "tomato": "#ff6347",
    "turquoise": "#40e0d0",
    "violet": "#ee82ee",
    "wheat": "#f5deb3",
    "white": "#ffffff",
    "whitesmoke": "#f5f5f5",
    "yellow": "#ffff00",
    "yellowgreen": "#9acd32"
}

export type Colors = keyof typeof ColorMapping

export const isColorName = (str: string) => {
    return (str in ColorMapping);
}

根据wiki上的描述,需要把16进制的颜色转换为RGB才能正确的设置样式,这里需要写一个工具类。

/**
 * 将16进制的颜色转换为RGB返回
 * @param hex - 16进制的颜色
 * @returns {number, number, number} 16进制的颜色的RGB表示
 */
export const hexToRgb = (hex: string) => {
    const matches = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)!;
    return {
        r: parseInt(matches[1], 16),
        g: parseInt(matches[2], 16),
        b: parseInt(matches[3], 16)
    }
}

3、实现简易版chalk

import supportTrueColor from "./supportTrueColor.js";
import {EscapeSequence1, EscapeSequence2, Styles} from "./ansi.js";
import {ColorMapping, Colors, isColorName} from "./color.js";
import {hexToRgb} from "./utils.js";

type colorType = "foreground" | "background"

export class Chalk {
    private prefix: string
    private suffix: string

    constructor() {
        if (!supportTrueColor()) {
            throw new Error("Not Supported TrueColor!")
        }
        this.prefix = ''
        this.suffix = ''
    }

    private escapeSequence(key: Styles, ...args: any[]) {
        this.prefix += EscapeSequence1(key, ...args)
        this.suffix += EscapeSequence2(key)
    }

    private rgb(t: colorType, r: number, g: number, b: number): this;
    private rgb(t: colorType, r: number, g: number, b: number, ...args: string[]): string;
    private rgb(t: colorType, r: number, g: number, b: number, ...args: string[]): string | this {
        this.escapeSequence(t as Styles, r, g, b);
        if (args.length > 0) {
            return this.build(...args);
        }
        return this;
    }

    build(...args: string[]) {
        const text = this.prefix + args.join(' ') + this.suffix;
        this.prefix = ''
        this.suffix = ''
        return text;
    }

    // style
    style(s: Styles): this;
    style(s: Styles, ...args: string[]): string;
    style(s: Styles, ...args: string[]): string | this {
        this.escapeSequence(s)
        if (args.length > 0) {
            return this.build(...args);
        }
        return this;
    }

    // color
    color(name: Colors): this;
    color(name: Colors, ...args: string[]): string;
    color(name: string): this;
    color(name: string, ...args: string[]): string;
    color(name: Colors | string, ...args: string[]): string | this {
        const {r, g, b} = isColorName(name) ? hexToRgb(ColorMapping[name as Colors]) : hexToRgb(name);
        return this.rgb("foreground", r, g, b, ...args)
    }

    // bgColor
    bgColor(name: Colors): this;
    bgColor(name: Colors, ...args: string[]): string;
    bgColor(name: string): this;
    bgColor(name: string, ...args: string[]): string;
    bgColor(name: Colors | string, ...args: string[]): string | this {
        const {r, g, b} = isColorName(name) ? hexToRgb(ColorMapping[name as Colors]) : hexToRgb(name);
        return this.rgb("background", r, g, b, ...args)
    }
}

export default new Chalk();

// const chalk = new Chalk();
// console.log(chalk.color("#ff9600").bgColor("skyblue").style("bold", "hello chalk!"));
// console.log(chalk.color("red").bgColor("pink").style("bold").build("hello chalk!"));

最后贴一下项目地址:https://github.com/xumeng03/chalk

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用 JavaScript 编写的记忆游戏(附源代码)   项目:JavaScript 记忆游戏(附源代码) 记忆检查游戏是一个使用 HTML5、CSS 和 JavaScript 开发的简单项目。这个游戏是关于测试你的短期 记忆技能。玩这个游戏 时,一系列图像会出现在一个盒子形状的区域中 。玩家必须找到两个相同的图像并单击它们以使它们消失。 如何运行游戏? 记忆游戏项目仅包含 HTML、CSS 和 JavaScript。谈到此游戏的功能,用户必须单击两个相同的图像才能使它们消失。 点击卡片或按下键盘键,通过 2 乘 2 旋转来重建鸟儿对,并发现隐藏在下面的图像! 如果翻开的牌面相同(一对),您就赢了,并且该对牌将从游戏中消失! 否则,卡片会自动翻面朝下,您需要重新尝试! 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox, 以获得更好、更优化的游戏体验。要玩游戏,首先,通过单击 memorygame-index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

眼眸流转

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值