chipmunkbot3/util/text_parser.js

126 lines
3.2 KiB
JavaScript

const { language } = require('minecraft-data')('1.20.4')
const colormap = {
black: '§0',
dark_blue: '§1',
dark_green: '§2',
dark_aqua: '§3',
dark_red: '§4',
dark_purple: '§5',
gold: '§6',
gray: '§7',
dark_gray: '§8',
blue: '§9',
green: '§a',
aqua: '§b',
red: '§c',
light_purple: '§d',
yellow: '§e',
white: '§f',
reset: '§r'
}
const ansimap = {
'§0': '\x1b[0m\x1b[30m',
'§1': '\x1b[0m\x1b[34m',
'§2': '\x1b[0m\x1b[32m',
'§3': '\x1b[0m\x1b[36m',
'§4': '\x1b[0m\x1b[31m',
'§5': '\x1b[0m\x1b[35m',
'§6': '\x1b[0m\x1b[33m',
'§7': '\x1b[0m\x1b[37m',
'§8': '\x1b[0m\x1b[90m',
'§9': '\x1b[0m\x1b[94m',
'§a': '\x1b[0m\x1b[92m',
'§b': '\x1b[0m\x1b[96m',
'§c': '\x1b[0m\x1b[91m',
'§d': '\x1b[0m\x1b[95m',
'§e': '\x1b[0m\x1b[93m',
'§f': '\x1b[0m\x1b[97m',
'§r': '\x1b[0m',
'§l': '\x1b[1m',
'§o': '\x1b[3m',
'§n': '\x1b[4m',
'§m': '\x1b[9m',
'§k': '\x1b[6m'
}
/**
* Parses a native minecraft text component in string form.
* @param {string} json_string - A text component string, such as the chat packet's 'message' property.
* @returns {object} Parsed message in { raw, clean, ansi } form.
*/
function parseText (json) {
let raw = parseJson(json, { color: 'reset' })
if (raw.startsWith('§r')) {
raw = raw.substring(2)
}
const clean = raw.replace(/§./g, '').replace(/§/g, '')
const ansi = raw.replace(/§[a-f0-9rlonmk]/g, (m) => ansimap[m])
return { raw, clean, ansi }
}
/**
* Parses a native minecraft text component in JSON form.
* @param {object} json - The json message.
* @param {object} parent - The parent json.
* @returns {string} The parsed raw string.
*/
function parseJson (json, parent) {
if (typeof json === 'string') {
json = { text: json }
} else if (Array.isArray(json)) {
const root = json.shift()
root.extra = json
json = root
}
json.color ??= parent.color
json.bold ??= parent.bold
json.italic ??= parent.italic
json.underlined ??= parent.underlined
json.strikethrough ??= parent.strikethrough
json.obfuscated ??= parent.obfuscated
let raw = ''
// if (json.color.startsWith('#'))
// raw += '§' + color
// else
raw += colormap[json.color] || ''
if (json.bold) raw += '§l'
if (json.italic) raw += '§o'
if (json.underlined) raw += '§n'
if (json.strikethrough) raw += '§m'
if (json.obfuscated) raw += '§k'
if (json.text) {
raw += json.text
}
if (json.translate) { // I checked with the native minecraft code. This is how Minecraft does the matching and group indexing. -hhhzzzsss
let format = language[json.translate]
if (typeof format !== 'string') format = json.fallback
if (typeof format !== 'string') format = json.translate
const _with = json.with ?? []
let i = 0
raw += format.replace(/%(?:(\d+)\$)?(s|%)/g, (g0, g1) => {
if (g0 === '%%') {
return '%'
} else {
const idx = g1 ? parseInt(g1) : i++
if (_with[idx]) {
return parseJson(_with[idx], json)
} else {
return ''
}
}
})
}
if (json.extra) {
json.extra.forEach((extra) => {
raw += parseJson(extra, json)
})
}
return raw
}
module.exports = parseText