acquerello
Version:
Template based terminal coloring made really easy.
74 lines (73 loc) • 2.68 kB
JavaScript
import { defaultStyles } from './codes.js';
import { convertColorSpec } from './spec.js';
export const templateMatcher = /{{2}([^{}]+?)}{2}/gi;
export function clean(raw) {
return raw.replaceAll(templateMatcher, '');
}
export function colorize(raw) {
// Create a new styles stack
let stylesStack = [];
let stylesInserted = false;
// For each tag in the string
let modified = raw.replaceAll(templateMatcher, (_, spec)=>{
const revert = [];
let replacement = '';
// Get all the styles - Whatever is not found in ansi-styles is ignored
const tokens = spec.trim().split(/\s+/).map((s)=>s.trim());
for (const token of tokens){
if (token === '-') {
// Remove a style
if (stylesStack.length) {
// First of all, remove the latest applied style
replacement += stylesStack.shift().reverse().map((s)=>s.close).join('');
// If there is a style to restore it, reapply it
if (stylesStack.length) {
replacement += stylesStack[0].map((s)=>s.open).join('');
}
}
break;
} else if (token === 'reset') {
// Forget all previously defined styles
stylesStack = [];
break;
} else {
// Search in custom styles first
const styles = customStyles.get(token) ?? [
token
];
for (const style of styles){
// Add a style
const code = convertColorSpec(style);
if (code) {
replacement += code.open;
revert.push(code);
}
}
}
}
// If anything was applied, append to the stack
if (revert.length) {
stylesInserted = true;
stylesStack.unshift(revert);
}
return replacement;
});
// Always make sure to reset codes at the end
if (stylesInserted) {
modified += defaultStyles.reset.close;
}
return modified;
}
export function applyStyle(content, ...styles) {
return colorize(`{{${styles.join(' ')}}}${content}{{-}}`);
}
export function addCustomStyle(name, ...styles) {
if (!/^[^\s{}]+$/.test(name)) {
throw new Error('The custom style name cannot contain spaces or curly braces');
}
customStyles.set(name, styles);
}
export function deleteCustomStyle(name) {
customStyles.delete(name);
}
export const customStyles = new Map();