154 lines
4.0 KiB
TypeScript
154 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 {
|
|
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(' ');
|
|
}
|
|
}
|