238 lines
6.5 KiB
JavaScript
238 lines
6.5 KiB
JavaScript
// https://github.com/janispritzkau/mc-chat-format
|
|
|
|
/**
|
|
* Converts a Minecraft chat component to a formatted string.
|
|
* */
|
|
export function format(component, options = {}) {
|
|
const text = formatString(convert(component, options), options.useAnsiCodes);
|
|
if (options.maxLineLength) {
|
|
let t = "", e = false, l = 0;
|
|
for (let c of text) {
|
|
if (c === "\x1b")
|
|
e = true;
|
|
else if (c === "m")
|
|
e = false;
|
|
else if (c === "\n")
|
|
l = 0;
|
|
t += c;
|
|
if (l === options.maxLineLength)
|
|
t += "\n", l = 0;
|
|
if (!e)
|
|
l += 1;
|
|
}
|
|
return t;
|
|
} else
|
|
return text;
|
|
}
|
|
|
|
/**
|
|
* Applies translations to a [Chat component](https://wiki.vg/Chat) and converts
|
|
* it to `StringComponent`.
|
|
*/
|
|
export function convert(component, options = {}) {
|
|
if (typeof component == "string") {
|
|
return options.keepOld ? {text: component} : convertOld(component);
|
|
}
|
|
if (component.extra) {
|
|
component.extra = component.extra.map(x => convert(x, options));
|
|
}
|
|
if (options.stripNonText) {
|
|
delete component.hoverEvent;
|
|
delete component.clickEvent;
|
|
delete component.insertion;
|
|
}
|
|
if (!options.keepOld) {
|
|
const {text, extra} = convertOld(component.text);
|
|
component.text = text;
|
|
if (extra && component.extra)
|
|
component.extra = [...extra, ...component.extra];
|
|
else if (extra && !component.extra)
|
|
component.extra = extra;
|
|
}
|
|
return component;
|
|
}
|
|
|
|
/**
|
|
* Converts a string formatted using the old formatting scheme
|
|
* to the current JSON chat system.
|
|
*/
|
|
export function convertOld(text) {
|
|
let c = {text: ""};
|
|
const extra = [];
|
|
for (const [i, t] of text.split(/ยง(.)/).entries()) {
|
|
if (i === 0) {
|
|
c.text = t;
|
|
} else if (i % 2 === 0) {
|
|
if (t.length !== 0)
|
|
extra.push({...c, text: t});
|
|
} else
|
|
switch (t) {
|
|
case "k":
|
|
c.obfuscated = true;
|
|
break;
|
|
case "l":
|
|
c.bold = true;
|
|
break;
|
|
case "m":
|
|
c.strikethrough = true;
|
|
break;
|
|
case "n":
|
|
c.underlined = true;
|
|
break;
|
|
case "o":
|
|
c.bold = true;
|
|
break;
|
|
case "r":
|
|
c = {text: c.text};
|
|
break;
|
|
case "0":
|
|
c.color = "black";
|
|
break;
|
|
case "1":
|
|
c.color = "dark_blue";
|
|
break;
|
|
case "2":
|
|
c.color = "dark_green";
|
|
break;
|
|
case "3":
|
|
c.color = "dark_aqua";
|
|
break;
|
|
case "4":
|
|
c.color = "dark_red";
|
|
break;
|
|
case "5":
|
|
c.color = "dark_purple";
|
|
break;
|
|
case "6":
|
|
c.color = "gold";
|
|
break;
|
|
case "7":
|
|
c.color = "gray";
|
|
break;
|
|
case "8":
|
|
c.color = "dark_gray";
|
|
break;
|
|
case "9":
|
|
c.color = "blue";
|
|
break;
|
|
case "a":
|
|
c.color = "green";
|
|
break;
|
|
case "b":
|
|
c.color = "aqua";
|
|
break;
|
|
case "c":
|
|
c.color = "red";
|
|
break;
|
|
case "d":
|
|
c.color = "light_purple";
|
|
break;
|
|
case "e":
|
|
c.color = "yellow";
|
|
break;
|
|
case "f":
|
|
c.color = "white";
|
|
break;
|
|
}
|
|
}
|
|
c = {text: c.text};
|
|
if (extra.length > 0)
|
|
c.extra = extra;
|
|
return c;
|
|
}
|
|
|
|
/** Flattens a nested `StringComponent`. */
|
|
export function flatten(component) {
|
|
const {text, extra, ...rest} = component;
|
|
const array = [{text, ...rest}];
|
|
if (extra)
|
|
array.push(...flattenArray(extra.map(c => {
|
|
if (typeof c == "string")
|
|
return [{text: c, ...rest}];
|
|
if (!('text' in c))
|
|
throw new Error("Not a StringComponent");
|
|
return flatten(c).map(c => ({...c, ...rest, ...c}));
|
|
})));
|
|
return array;
|
|
}
|
|
|
|
/** Converts a `StringComponent` to plain text and can format it using ANSI codes. */
|
|
export function formatString(component) {
|
|
return flatten(component).map((c) => {
|
|
let codes = colorToAnsiCode(c.color);
|
|
if (c.bold)
|
|
codes += "\u00a7l";
|
|
if (c.italic)
|
|
codes += "\u00a7o";
|
|
if (c.underlined)
|
|
codes += "\u00a7n";
|
|
if (c.strikethrough)
|
|
codes += "\u00a7m";
|
|
return codes ? codes + c.text + "\u00a7r" : c.text;
|
|
}).join("");
|
|
}
|
|
|
|
function colorToAnsiCode(color) {
|
|
let code = "";
|
|
switch (color) {
|
|
case "black":
|
|
code += "0";
|
|
break;
|
|
case "dark_blue":
|
|
code += "1";
|
|
break;
|
|
case "dark_green":
|
|
code += "2";
|
|
break;
|
|
case "dark_aqua":
|
|
code += "3";
|
|
break;
|
|
case "dark_red":
|
|
code += "4";
|
|
break;
|
|
case "dark_purple":
|
|
code += "5";
|
|
break;
|
|
case "gold":
|
|
code += "6";
|
|
break;
|
|
case "gray":
|
|
code += "7";
|
|
break;
|
|
case "dark_gray":
|
|
code += "8";
|
|
break;
|
|
case "blue":
|
|
code += "9";
|
|
break;
|
|
case "green":
|
|
code += "a";
|
|
break;
|
|
case "aqua":
|
|
code += "b";
|
|
break;
|
|
case "red":
|
|
code += "c";
|
|
break;
|
|
case "light_purple":
|
|
code += "d";
|
|
break;
|
|
case "yellow":
|
|
code += "e";
|
|
break;
|
|
case "white":
|
|
code += "f";
|
|
break;
|
|
}
|
|
return code && "\u00a7" + code;
|
|
}
|
|
|
|
function flattenArray(array) {
|
|
return [].concat(...array);
|
|
}
|
|
|
|
/** @deprecated Use `format(convert(component))` instead */
|
|
export function chatToText(component, translation) {
|
|
return format(component, {translation});
|
|
}
|