132 lines
2.4 KiB
JavaScript
132 lines
2.4 KiB
JavaScript
"use strict";
|
|
|
|
const BOLD = "\x02";
|
|
const COLOR = "\x03";
|
|
const RESET = "\x0f";
|
|
const REVERSE = "\x16";
|
|
const ITALIC = "\x1d";
|
|
const UNDERLINE = "\x1f";
|
|
|
|
const colorRx = /^(\d{1,2})(?:,(\d{1,2}))?/;
|
|
const controlCodesRx = /[\u0000-\u001F]/g;
|
|
|
|
function parseStyle(text) {
|
|
const result = [];
|
|
let start = 0;
|
|
let position = 0;
|
|
|
|
let colorCodes, bold, textColor, bgColor, reverse, italic, underline;
|
|
|
|
const resetStyle = () => {
|
|
bold = false;
|
|
textColor = undefined;
|
|
bgColor = undefined;
|
|
reverse = false;
|
|
italic = false;
|
|
underline = false;
|
|
};
|
|
resetStyle();
|
|
|
|
const emitFragment = () => {
|
|
const textPart = text.slice(start, position);
|
|
start = position + 1;
|
|
|
|
const processedText = textPart.replace(controlCodesRx, "");
|
|
|
|
if (!processedText.length) {
|
|
return;
|
|
}
|
|
|
|
result.push({
|
|
bold,
|
|
textColor,
|
|
bgColor,
|
|
reverse,
|
|
italic,
|
|
underline,
|
|
text: processedText
|
|
});
|
|
};
|
|
|
|
while (position < text.length) {
|
|
switch (text[position]) {
|
|
|
|
case RESET:
|
|
emitFragment();
|
|
resetStyle();
|
|
break;
|
|
|
|
case BOLD:
|
|
emitFragment();
|
|
bold = !bold;
|
|
break;
|
|
|
|
case COLOR:
|
|
emitFragment();
|
|
|
|
colorCodes = text.slice(position + 1).match(colorRx);
|
|
|
|
if (colorCodes) {
|
|
textColor = Number(colorCodes[1]);
|
|
bgColor = Number(colorCodes[2]);
|
|
if (Number.isNaN(bgColor)) {
|
|
bgColor = undefined;
|
|
}
|
|
position += colorCodes[0].length;
|
|
} else {
|
|
textColor = undefined;
|
|
bgColor = undefined;
|
|
}
|
|
start = position + 1;
|
|
break;
|
|
|
|
case REVERSE:
|
|
emitFragment();
|
|
reverse = !reverse;
|
|
break;
|
|
|
|
case ITALIC:
|
|
emitFragment();
|
|
italic = !italic;
|
|
break;
|
|
|
|
case UNDERLINE:
|
|
emitFragment();
|
|
underline = !underline;
|
|
break;
|
|
}
|
|
position += 1;
|
|
}
|
|
|
|
emitFragment();
|
|
|
|
return result;
|
|
}
|
|
|
|
const properties = ["bold", "textColor", "bgColor", "italic", "underline", "reverse"];
|
|
|
|
function prepare(text) {
|
|
return parseStyle(text)
|
|
.filter(fragment => fragment.text.length)
|
|
.reduce((prev, curr, i) => {
|
|
if (i === 0) {
|
|
return prev.concat([curr]);
|
|
}
|
|
|
|
const lastEntry = prev[prev.length - 1];
|
|
if (properties.some(key => curr[key] !== lastEntry[key])) {
|
|
return prev.concat([curr]);
|
|
}
|
|
|
|
lastEntry.text += curr.text;
|
|
return prev;
|
|
}, [])
|
|
.map((fragment, i, array) => {
|
|
fragment.start = i === 0 ? 0 : array[i - 1].end;
|
|
fragment.end = fragment.start + fragment.text.length;
|
|
return fragment;
|
|
});
|
|
}
|
|
|
|
module.exports = prepare;
|