service-irc/irc/format.ts

155 lines
4.0 KiB
TypeScript

import { thousandsSeparator, toHHMMSS, timeSince } from '@squeebot/core/lib/common';
import { approximateB16Color, Formatter } from '@squeebot/core/lib/types';
export class IRCFormatter extends Formatter {
public formatting = {
bold: {start: '\u0002', end: '\u000F'},
italics: {start: '\u0016', end: '\u000F'},
emphasis: {start: '\u0016', end: '\u000F'},
underline: {start: '\u001F', end: '\u000F'},
action: {start: '\x01ACTION ', end: '\x01'},
};
public colorEscape = '\u000F';
public colors: {[key: string]: string} = {
black: '\u00031',
darkblue: '\u00032',
green: '\u00033',
red: '\u00034',
brown: '\u00035',
purple: '\u00036',
gold: '\u00037',
yellow: '\u00038',
limegreen: '\u00039',
cyan: '\u000310',
lightblue: '\u000311',
blue: '\u000312',
pink: '\u000313',
darkgray: '\u000314',
gray: '\u000315',
grey: '\u000315',
white: '\u00030',
};
public color(color: string, msg: string): string {
// Approximate a hex color to one of IRC colors
if (color.indexOf('#') === 0) {
color = approximateB16Color(color);
}
if (!this.supportColors) {
return msg;
}
if (!this.colors[color]) {
return msg;
}
return this.colors[color] + msg + this.colorEscape;
}
public strip(msg: string): string {
// eslint-disable-next-line no-control-regex
return msg.replace(/(\x03\d{0,2}(,\d{0,2})?)/g, '').replace(/[\x0F\x02\x16\x1F]/g, '');
}
compose(objs: any): any {
const str = [];
for (const i in objs) {
const elem = objs[i];
const elemType = elem[0];
let elemValue = elem[1];
const elemParams = elem[2];
if (!elemValue) {
continue;
}
let valueColor = null;
// Special types
if (elemParams && elemParams.type) {
switch (elemParams.type) {
case 'time':
elemValue = new Date(elemValue).toString();
break;
case 'metric':
elemValue = thousandsSeparator(elemValue);
break;
case 'timesince':
elemValue = timeSince(elemValue);
break;
case 'duration':
elemValue = toHHMMSS(elemValue);
break;
case 'description':
valueColor = 'blue';
elemValue = `"${elemValue}"`;
break;
}
}
// Currently, disregard image fields.
if (elemType === 'image') {
continue;
}
// Bold value
if (elemType === 'bold' || elemType === 'b' || elemType === 'strong') {
elemValue = this.format('bold', elemValue);
}
// Italic value
if (elemType === 'italic' || elemType === 'i' || elemType === 'em' || elemType === 'emphasis') {
elemValue = this.format('italic', elemValue);
}
// Underlined value
if (elemType === 'underline' || elemType === 'ul') {
elemValue = this.format('underline', elemValue);
}
// Colorize the value
if (elemParams && elemParams.color) {
valueColor = elemParams.color;
}
// Add the label, if present
if (elemParams && elemParams.label) {
// Set label color to default
let labelColor = 'green';
if (elemParams.color) {
labelColor = elemParams.color;
}
if (!valueColor) {
valueColor = 'blue';
}
// Handle array label
// Prefer the icon over the text version.
let label = elemParams.label;
if (typeof label === 'object') {
label = label[0];
} else {
label = label + ':';
}
if (valueColor && valueColor === labelColor) {
str.push(this.color(valueColor, label + ' ' + elemValue));
} else {
str.push(this.color(labelColor, label) + ' ' + (valueColor ? this.color(valueColor, elemValue) : elemValue));
}
} else {
str.push(valueColor ? this.color(valueColor, elemValue) : elemValue);
}
}
// May return an object, but your protocol must support it.
return str.join(' ');
}
}