101 lines
3 KiB
JavaScript
101 lines
3 KiB
JavaScript
|
const { colors, formatting, reset } = require('../formatting.json')
|
||
|
const { normalize, intToRgb, getChangedFormatting } = require('../utility')
|
||
|
|
||
|
const colormap = Object.fromEntries(colors.map(color => [color.name, color.ansi]))
|
||
|
const formatmap = Object.fromEntries(formatting.map(format => [format.name, format.ansi]))
|
||
|
const colorcodemap = Object.fromEntries(colors.map(color => [color.code, color.ansi]))
|
||
|
const formatcodemap = Object.fromEntries(formatting.map(format => [format.code, format.ansi]))
|
||
|
const baseColors = colors.map(color => intToRgb(color.rgb))
|
||
|
|
||
|
function ansiStringify (text, { lang = {}, previousText, parent } = {}) {
|
||
|
text = normalize(text)
|
||
|
|
||
|
let string = getFormatting(text, previousText, parent)
|
||
|
|
||
|
if (text.text != null) string += preprocessText(text.text)
|
||
|
else if (text.translate != null) {
|
||
|
let format
|
||
|
if (Object.hasOwn(lang, text.translate)) format = lang[text.translate]
|
||
|
else if (text.fallback != null) format = text.fallback
|
||
|
else format = text.translate
|
||
|
|
||
|
const _with = text.with || []
|
||
|
let i = 0
|
||
|
|
||
|
string += preprocessText(format).replace(/%(?:(\d+)\$)?(s|%)/g, (g0, g1) => {
|
||
|
if (g0 === '%%') return '%'
|
||
|
|
||
|
const idx = g1 ? parseInt(g1) : i++
|
||
|
if (_with[idx]) {
|
||
|
return ansiStringify(_with[idx], { lang, previousText: text, parent: text }) + getFormatting(text, _with[idx], parent)
|
||
|
}
|
||
|
|
||
|
return ''
|
||
|
})
|
||
|
}
|
||
|
else if (text.selector != null) string += preprocessText(text.selector)
|
||
|
else if (text.keybind) {
|
||
|
// TODO
|
||
|
}
|
||
|
|
||
|
if (text.extra) {
|
||
|
let previousChild = text
|
||
|
for (const child of text.extra) {
|
||
|
string += ansiStringify(child, { lang, previousText: previousChild, parent: text })
|
||
|
previousChild = child
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return string
|
||
|
}
|
||
|
|
||
|
function getFormatting (text, previousText, parent) {
|
||
|
const format = getChangedFormatting(text, previousText, parent)
|
||
|
let string = ''
|
||
|
|
||
|
if ('color' in format) {
|
||
|
if (format.color && format.color[0] === '#') {
|
||
|
const rgb = parseInt(format.color.substring(1), 16) & 0xffffff
|
||
|
const [r, g, b] = intToRgb(rgb)
|
||
|
|
||
|
string += `\x1b[38;2;${r};${g};${b}m`
|
||
|
}
|
||
|
else if (colormap[format.color]) string += colormap[format.color]
|
||
|
else if (parent) string += reset.ansi
|
||
|
}
|
||
|
|
||
|
if (format.bold) string += formatmap.bold
|
||
|
if (format.italic) string += formatmap.italic
|
||
|
if (format.underlined) string += formatmap.underlined
|
||
|
if (format.strikethrough) string += formatmap.strikethrough
|
||
|
if (format.obfuscated) string += formatmap.obfuscated
|
||
|
|
||
|
return string
|
||
|
}
|
||
|
|
||
|
function preprocessText (input) {
|
||
|
let string = ''
|
||
|
|
||
|
for (let i = 0; i < input.length; i++) {
|
||
|
const c = input[i]
|
||
|
|
||
|
if (c === '§') {
|
||
|
if ((i + 1) >= input.length) break
|
||
|
|
||
|
const code = input.substring(i, i + 2)
|
||
|
i++
|
||
|
|
||
|
if (colorcodemap[code]) string += colorcodemap[code]
|
||
|
else if (formatcodemap[code]) string += formatcodemap[code]
|
||
|
else if (code === reset.code) string += reset.ansi
|
||
|
|
||
|
continue
|
||
|
}
|
||
|
else string += c
|
||
|
}
|
||
|
|
||
|
return string
|
||
|
}
|
||
|
|
||
|
module.exports = ansiStringify
|