UNPKG

@gesslar/colours

Version:

256 colours for your terminal expressions. you're welcome.

168 lines (145 loc) 4.82 kB
/** * @file 256 colours for your terminal expressions. Template literal-based * ANSI color library. * * Supports 256-color palette, granular styles, aliases, and clean syntax for * terminal output. * * @author gesslar * @version 0.0.1 */ /** Regex pattern for numbered color codes like {F045} or {B196} */ const numbered = /\{(?<kind>[FB])?(?<number>\d{1,3})\}/g /** Regex pattern for reset codes like {/} */ const reset = /\{\/\}/g /** Regex pattern for alias codes like {red} or {green} */ const aliases = /\{(?<alias>.+?)\}/g /** Regex pattern for style codes like {<BU} (open) or {BU>} (close) */ const styles = /\{<(?<open>[BRDFIORSU]+)\}|\{(?<close>[BRDFIORSU]+)>}/g /** * Template literal function for colorizing terminal output with ANSI escape codes. * Processes color codes, styles, aliases, and reset commands in a clean pipeline. * * @param {Array<*>} strings - Template literal string parts * @param {...any} values - Template literal interpolated values * @returns {string} Formatted string with ANSI escape codes * @example * c`{F045}Running:{/} {red}${testName}{/}` * c`{<BU}Bold underlined{B>} just underlined{/}` */ export default function c(strings, ...values) { return values .reduce((acc, curr, index) => `${acc}${curr}${strings[index+1]}`, strings[0]) .replaceAll(aliases, convertAliases) .replaceAll(numbered, convertNumbered) .replaceAll(styles, convertStyles) .replaceAll(reset, convertResets) } /** PROPERTIES/SUB FUNCTIONS */ /** * Alias management system for creating semantic color names * * @namespace */ c.alias = { /** @type {Map<string, string>} Storage for alias mappings */ aliases: new Map(), /** * Set an alias mapping * * @param {string} alias - The alias name (e.g., "red") * @param {string} replacement - The replacement code (e.g., "{F196}") */ set: function(alias,replacement) { this.aliases.set(alias, replacement) }, /** * Delete an alias mapping * * @param {string} alias - The alias name to remove */ del: function(alias) { this.aliases.delete(alias) }, } /** * Convert alias codes to their replacement values * * @param {string} code - The matched alias code (e.g., "{red}") * @param {...any} args - Regex match arguments, last element contains named groups * @returns {string} The replacement code or original if no alias found */ function convertAliases(code, ...args) { const {alias} = args.at(-1) ?? {} if(!alias) return code return c.alias.aliases.get(alias) ?? code } /** Map of style codes to their ANSI "off" sequences */ const offStyles = new Map([ ["B", "\x1b[22m"], // bright off ["D", "\x1b[22m"], // dim off ["F", "\x1b[25m"], // flash off ["I", "\x1b[23m"], // italics off ["O", "\x1b[55m"], // overline off ["R", "\x1b[27m"], // reverse video off ["S", "\x1b[29m"], // strikethrough off ["U", "\x1b[24m"], // underline off ]) /** Map of style codes to their ANSI "on" sequences */ const onStyles = new Map([ ["B", "\x1b[1m"], // bright on ["D", "\x1b[2m"], // dim on ["F", "\x1b[5m"], // flash on ["I", "\x1b[3m"], // italics on ["O", "\x1b[53m"], // overline on ["R", "\x1b[7m"], // reverse video on ["S", "\x1b[9m"], // strikethrough on ["U", "\x1b[4m"], // underline on ]) /** * Convert style codes to ANSI escape sequences * * @param {string} _ - The matched style code (e.g., "{<BU}" or "{BU>}") * @param {...any} args - Regex match arguments, last element contains named groups * @returns {string} ANSI escape sequences for the requested styles */ function convertStyles(_, ...args) { const {open,close} = args.at(-1) ?? {} /** @type {string} Combined ANSI sequences for all requested styles */ const codes = (open || close || "") .split("") .map((/** @type {string} */ style) => (open && onStyles.get(style)) || (close && offStyles.get(style)) || style ) .join("") return codes } /** * Convert numbered color codes to ANSI escape sequences * * @param {string} code - The matched color code (e.g., "{F045}" or "{B196}") * @param {...any} args - Regex match arguments, last element contains named groups * @returns {string} ANSI escape sequence for the color or original code if invalid */ function convertNumbered(code, ...args) { const {kind,number} = args.at(-1) ?? {} if(!kind || !number || Number.isNaN(number)) return code /** @type {number} Parsed color number for validation */ const colourNumber = Number(number) if(colourNumber < 0 || colourNumber > 255) return code return kind === "F" ? `\x1b[38;5;${number}m` : `\x1b[48;5;${number}m` } /** * Convert reset codes to ANSI reset sequence * * @returns {string} ANSI reset sequence */ function convertResets() { return "\x1b[0m" }